MyViewController *myVC = [[MyViewController alloc]init];
//創(chuàng)建動(dòng)畫(huà)
CATransition *animation = [CATransition animation];
//設(shè)置運(yùn)動(dòng)軌跡的速度
animation.timingFunction = UIViewAnimationCurveEaseInOut;
//設(shè)置動(dòng)畫(huà)類型為立方體動(dòng)畫(huà)
animation.type = @"cube";
//設(shè)置動(dòng)畫(huà)時(shí)長(zhǎng)
animation.duration =0.5f;
//設(shè)置運(yùn)動(dòng)的方向
animation.subtype =kCATransitionFromRight;
//控制器間跳轉(zhuǎn)動(dòng)畫(huà)
[[UIApplication sharedApplication].keyWindow.layer addAnimation:animation forKey:nil];
[self presentViewController:myVC animated:NO completion:nil];
下面附上一些常用的動(dòng)畫(huà)類型:
Fade = 1, //淡入淡出
Push, //推擠
Reveal, //揭開(kāi)
MoveIn, //覆蓋
Cube, //立方體
SuckEffect, //吮吸
OglFlip, //翻轉(zhuǎn)
RippleEffect, //波紋
PageCurl, //翻頁(yè)
PageUnCurl, //反翻頁(yè)
CameraIrisHollowOpen, //開(kāi)鏡頭
CameraIrisHollowClose, //關(guān)鏡頭
CurlDown, //下翻頁(yè)
CurlUp, //上翻頁(yè)
FlipFromLeft, //左翻轉(zhuǎn)
附上簡(jiǎn)書(shū)大神的文章:http://www.reibang.com/p/09b7e5ff371c
FlipFromRight, //右翻轉(zhuǎn)
簡(jiǎn)單自定義ViewController跳轉(zhuǎn)動(dòng)畫(huà)
在學(xué)習(xí)iOS動(dòng)畫(huà)時(shí)看到,別人炫酷的動(dòng)畫(huà)效果一直是我學(xué)習(xí)的動(dòng)力,在學(xué)習(xí)如何自定義后發(fā)現(xiàn)其實(shí)并沒(méi)那么難档冬,一些漸變膘茎,翻轉(zhuǎn),平移等在UIView上能實(shí)現(xiàn)的動(dòng)畫(huà)都可以放到跳轉(zhuǎn)動(dòng)畫(huà)里酷誓,做完例子你也可以.
原理
當(dāng)我們進(jìn)行視圖切換的時(shí)候披坏,無(wú)論是push,pop還是通過(guò)PresentModal和dismiss時(shí)盐数,我們可以把跳轉(zhuǎn)動(dòng)畫(huà)分割為三個(gè)部分棒拂,
1:第一個(gè)視圖控制器顯示。
2:臨時(shí)視圖控制器 顯示動(dòng)畫(huà)效果(并不是真的存在這個(gè)控制器玫氢,其實(shí)只有一個(gè)containerView)
3:顯示第二個(gè)視圖控制器帚屉。用形象一點(diǎn)的說(shuō)法,我們可以將第二部分也看做是一個(gè)臨時(shí)的視圖控制器漾峡,他執(zhí)行一段關(guān)于UIView的動(dòng)畫(huà)攻旦,我們只要讓動(dòng)畫(huà)的開(kāi)始界面與控制器1一樣,結(jié)束界面與視圖控制器2一樣生逸。當(dāng)動(dòng)畫(huà)執(zhí)行結(jié)束牢屋,執(zhí)行到第三步時(shí),把臨時(shí)的視圖控制器釋放槽袄。這樣只要稍微實(shí)現(xiàn)一些UIView烙无,CALayer的動(dòng)畫(huà),
具體的實(shí)現(xiàn)方法以下圖的效果為例子:
用到的協(xié)議及方法
@protocol UIViewControllerAnimatedTransitioning
實(shí)現(xiàn)這個(gè)協(xié)議的對(duì)象就相當(dāng)于是之前說(shuō)到的臨時(shí)視圖控制器遍尺,協(xié)議中主要用到的兩個(gè)方法是:
//這個(gè)方法中我們只要返回頁(yè)面跳轉(zhuǎn)動(dòng)畫(huà)的執(zhí)行時(shí)間
-(NSTimeInterval)transitionDuration:(id < UIViewControllerContextTransitioning >)transitionContext;
//在這個(gè)方法中實(shí)現(xiàn)具體動(dòng)畫(huà)
-(void)animateTransition:(id < UIViewControllerContextTransitioning >)transitionContext;
第二個(gè)方法是跳轉(zhuǎn)動(dòng)畫(huà)核心內(nèi)容截酷,方法中的參數(shù)transitionContext是當(dāng)前臨時(shí)控制器界面的上下文。通過(guò)上下文狮鸭,我們先拿到臨時(shí)視圖控制器的背景視圖containerView合搅,他已經(jīng)有一個(gè)子視圖,即fromViewController.view歧蕉。我們要做的是灾部,先獲得toViewController
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
然后把當(dāng)前視圖加到內(nèi)容視圖上
[[transitionContext containerView] addSubview:toVC.view];
剩下的部分就可以發(fā)揮我們的系統(tǒng)核心動(dòng)畫(huà)的學(xué)習(xí)水平,比如修改toVC.view的frame惯退,從下方旋轉(zhuǎn)彈出等等赌髓。而要實(shí)現(xiàn)Demo里的效果,我們需要CAShapeLayer來(lái)給toView做遮擋催跪,然后從修改ShapeLayer.path屬性锁蠕,從一個(gè)小圓變成一個(gè)囊括全屏的大圓,小圓大圓我們通過(guò)UIBezierPath畫(huà)出來(lái)懊蒸,對(duì)于ShapeLayer和UIBezierPath不熟悉的同學(xué)可以先去補(bǔ)習(xí)一下荣倾,這里具體的使用也不復(fù)雜,也可以直接看下面的代碼學(xué)習(xí)骑丸。
//應(yīng)用程序的屏幕高度
#define kWindowH [UIScreen mainScreen].bounds.size.height
//應(yīng)用程序的屏幕寬度
#define kWindowW [UIScreen mainScreen].bounds.size.width
_circleCenterRect = CGRectMake(120, 320, 50, 50);
//圓圈1--小圓
UIBezierPath *smallCircleBP = [UIBezierPath bezierPathWithOvalInRect:_circleCenterRect];
//圓圈2--大圓
//以_circleCenterRect的中心為圓心
CGFloat centerX = _circleCenterRect.origin.x+_circleCenterRect.size.width/2;
CGFloat centerY = _circleCenterRect.origin.y+_circleCenterRect.size.height/2;
//找出圓心到頁(yè)面4個(gè)角 最長(zhǎng)的距離 作為半徑
CGFloat r1 = (kWindowW-centerX)>centerX?(kWindowW-centerX):centerX;
CGFloat r2 = (kWindowW-centerY)>centerY?(kWindowW-centerY):centerY;
CGFloat radius = sqrt((r1 * r1) + (r2 * r2));
UIBezierPath *bigCircleBP = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(_circleCenterRect, -radius, -radius)];
畫(huà)完圓后通過(guò)CABasicAnimation執(zhí)行:
//設(shè)置maskLayer
CAShapeLayer *maskLayer = [CAShapeLayer layer];//將它的 path 指定為最終的 path 來(lái)避免在動(dòng)畫(huà)完成后會(huì)回彈
toVC.view.layer.mask = maskLayer;
maskLayer.path = bigCircleBP.CGPath;
//執(zhí)行動(dòng)畫(huà)
CABasicAnimation *maskLayerAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
maskLayerAnimation.fromValue = (__bridge id)(smallCircleBP.CGPath);
maskLayerAnimation.toValue = (__bridge id)((bigCircleBP.CGPath));
maskLayerAnimation.duration = [self transitionDuration:transitionContext];
maskLayerAnimation.delegate = self;
[maskLayer addAnimation:maskLayerAnimation forKey:@"path"];
返回時(shí)候的動(dòng)畫(huà)效果和上面的代碼基本相同舌仍,只用將大圓和小圓的順序?qū)φ{(diào)妒貌,完成了跳轉(zhuǎn)動(dòng)畫(huà)最核心的部分后就是怎么使用這個(gè)對(duì)象了,無(wú)論是navigation和模態(tài)跳轉(zhuǎn)铸豁,系統(tǒng)都給我們提供了回調(diào)方法灌曙,我們只需要實(shí)現(xiàn)方法,然后把我們之前寫好的動(dòng)畫(huà)對(duì)象返回就可以了节芥。由于給視圖添加了shapelayer在刺,可以在CABasicAnimation的代理方法里實(shí)現(xiàn)。
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
//告訴 系統(tǒng)這個(gè) transition 完成
[self.transitionContext completeTransition:![self.transitionContext transitionWasCancelled]];
//清除 fromVC 的 mask
[self.transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey].view.layer.mask = nil;
[self.transitionContext viewControllerForKey:UITransitionContextToViewControllerKey].view.layer.mask = nil;
}
@protocol UINavigationControllerDelegate
這是修改Navigation跳轉(zhuǎn)動(dòng)畫(huà)需要實(shí)現(xiàn)的協(xié)議头镊,當(dāng)我們通過(guò)pop或者push進(jìn)行跳轉(zhuǎn)時(shí)蚣驼,都會(huì)調(diào)用下面的方法(協(xié)議的其他方法由于暫時(shí)用不到,所以就不介紹了)拧晕,我們可以看到返回值是id <UIViewControllerAnimatedTransitioning>隙姿,就是我們之前編寫的動(dòng)畫(huà)對(duì)象。
- (nullable id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC;
方法中的operation參數(shù)是一個(gè)枚舉類型厂捞,我們可以判斷它的值是 UINavigationControllerOperationPush還是
UINavigationControllerOperationPop來(lái)區(qū)別當(dāng)前的跳轉(zhuǎn)方式输玷。
@protocol UIViewControllerTransitioningDelegate
這是修改模態(tài)跳轉(zhuǎn)動(dòng)畫(huà)需要實(shí)現(xiàn)的協(xié)議,我們進(jìn)行跳轉(zhuǎn)PresentModal和dismiss時(shí)會(huì)分別調(diào)用兩個(gè)方法:
//PresentModal跳轉(zhuǎn)回調(diào)方法
- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source;
//dismiss跳轉(zhuǎn)回調(diào)方法
- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed;
這兩個(gè)方法的返回值和上面navigation回調(diào)方法的返回值一樣靡馁,我們只需要初始化我們的實(shí)現(xiàn)了UIViewControllerTransitioningDelegate協(xié)議的動(dòng)畫(huà)對(duì)象就可以了欲鹏。具體的實(shí)現(xiàn)以及效果可以查看文章末尾附上的Demo。
navigation跳轉(zhuǎn)需要注意的地方
在使用Navigation跳轉(zhuǎn)的時(shí)候臭墨,我們希望視圖1跳轉(zhuǎn)到視圖2和視圖2返回視圖1有自定義動(dòng)畫(huà)時(shí)赔嚎,我們只用在視圖1中將設(shè)置視圖1的navigation的delagate。其次delegate的設(shè)置最好放在viewWillAppear中胧弛。
demo所實(shí)現(xiàn)的最終效果只出現(xiàn)在點(diǎn)擊按鈕時(shí)的跳轉(zhuǎn)動(dòng)畫(huà)尤误,而不包括像navigation側(cè)滑返回那樣的手勢(shì)動(dòng)畫(huà)。如何怕側(cè)滑效果不統(tǒng)一结缚,我們可以先把側(cè)滑返回的效果關(guān)閉:
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
// TODO:手勢(shì)跳轉(zhuǎn)動(dòng)畫(huà)實(shí)現(xiàn)方法(坑 待填)