iOS 在控制器間跳轉(zhuǎn)實(shí)現(xiàn)過(guò)渡動(dòng)畫(huà)

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)方法(坑 待填)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末损晤,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子红竭,更是在濱河造成了極大的恐慌尤勋,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件茵宪,死亡現(xiàn)場(chǎng)離奇詭異最冰,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)稀火,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門暖哨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人凰狞,你說(shuō)我怎么就攤上這事鹿蜀』郏” “怎么了服球?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵茴恰,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我斩熊,道長(zhǎng)往枣,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任粉渠,我火速辦了婚禮分冈,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘霸株。我一直安慰自己雕沉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布去件。 她就那樣靜靜地躺著坡椒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪尤溜。 梳的紋絲不亂的頭發(fā)上倔叼,一...
    開(kāi)封第一講書(shū)人閱讀 51,598評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音宫莱,去河邊找鬼丈攒。 笑死,一個(gè)胖子當(dāng)著我的面吹牛授霸,可吹牛的內(nèi)容都是我干的巡验。 我是一名探鬼主播,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼碘耳,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼显设!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起藏畅,我...
    開(kāi)封第一講書(shū)人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤敷硅,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后愉阎,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體绞蹦,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年榜旦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了幽七。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡溅呢,死狀恐怖澡屡,靈堂內(nèi)的尸體忽然破棺而出猿挚,到底是詐尸還是另有隱情,我是刑警寧澤驶鹉,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布绩蜻,位于F島的核電站,受9級(jí)特大地震影響室埋,放射性物質(zhì)發(fā)生泄漏办绝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一姚淆、第九天 我趴在偏房一處隱蔽的房頂上張望孕蝉。 院中可真熱鬧,春花似錦腌逢、人聲如沸降淮。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)佳鳖。三九已至,卻和暖如春窍蓝,著一層夾襖步出監(jiān)牢的瞬間腋颠,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工吓笙, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留淑玫,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓面睛,卻偏偏與公主長(zhǎng)得像絮蒿,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子叁鉴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容