iOS動畫(四) --自定義轉(zhuǎn)場動畫

image

本文記錄分享下自定義轉(zhuǎn)場動畫的實現(xiàn)方法憔儿,具體到動畫效果:新浪微博圖集瀏覽轉(zhuǎn)場效果、手勢過渡動畫、網(wǎng)易音樂啟動屏轉(zhuǎn)場動畫榆俺、開關(guān)門動畫、全屏側(cè)滑返回效果 的代碼可以到Github WSLTransferAnimation下載查看坞淮,注釋還算清晰茴晋。

模態(tài)化present和dismiss 自定義轉(zhuǎn)場

1、創(chuàng)建一個遵循<UIViewControllerAnimatedTransitioning>協(xié)議的動畫過渡管理對象回窘,并實現(xiàn)如下兩個方法:

//返回動畫事件
- (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext{
    return 0.3;
}
//所有的過渡動畫事務(wù)都在這個方法里面完成
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext{

 //取出轉(zhuǎn)場前后的視圖控制器
  UIViewController * fromVC = (UIViewController *)[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
  UIViewController * toVC = (UIViewController *)[transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

 //取出轉(zhuǎn)場前后視圖控制器上的視圖view
    UIView * toView = [transitionContext viewForKey:UITransitionContextToViewKey];
    UIView * fromView = [transitionContext viewForKey:UITransitionContextFromViewKey];

 //這里有個重要的概念containerView诺擅,要做轉(zhuǎn)場動畫的視圖就必須要加入containerView上才能進行,可以理解containerView管理著所有做轉(zhuǎn)場動畫的視圖
    UIView *containerView = [transitionContext containerView];

  //如果加入了手勢交互轉(zhuǎn)場啡直,就需要根據(jù)手勢交互動作是否完成/取消來做操作烁涌,完成標(biāo)記YES,取消標(biāo)記NO付枫,必須標(biāo)記烹玉,否則系統(tǒng)認(rèn)為還處于動畫過程中,會出現(xiàn)無法交互之類的bug
   [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
     if ([transitionContext transitionWasCancelled]) { 
    //如果取消轉(zhuǎn)場
          }else{
   //完成轉(zhuǎn)場
     }
}

2阐滩、自定義一個繼承于UIPercentDrivenInteractiveTransition的手勢過渡管理對象二打,可以根據(jù)手勢需要設(shè)置控制動畫轉(zhuǎn)場進度的百分比。

//必要調(diào)用實現(xiàn)的系統(tǒng)方法

//手勢過程中掂榔,通過updateInteractiveTransition設(shè)置轉(zhuǎn)場過程動畫進行的百分比继效,然后系統(tǒng)會根據(jù)百分比自動布局動畫控件,不用我們控制了
 [self updateInteractiveTransition:percentComplete];
//完成轉(zhuǎn)場操作
 [self finishInteractiveTransition];
//取消轉(zhuǎn)場操作
 [self cancelInteractiveTransition];

3装获、轉(zhuǎn)場時最上層的視圖控制器需要遵循<UIViewControllerTransitioningDelegate>的協(xié)議瑞信,并設(shè)置為代理,并實現(xiàn)如下代理方法:

//設(shè)置轉(zhuǎn)場代理
self.transitioningDelegate = self;

#pragma mark -- UIViewControllerTransitioningDelegate

//返回一個處理present動畫過渡的對象
-(id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source{
    return self.transitionAnimation;
}
//返回一個處理dismiss動畫過渡的對象
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed{
    //這里我們初始化dismissType
    self.transitionAnimation.transitionType = WSLTransitionOneTypeDissmiss;
    return self.transitionAnimation;
}
//返回一個處理present手勢過渡的對象 
- (nullable id <UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id <UIViewControllerAnimatedTransitioning>)animator{
    return self.transitionInteractive;
}
//返回一個處理dismiss手勢過渡的對象
- (nullable id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id <UIViewControllerAnimatedTransitioning>)animator{
    return self.transitionInteractive;
}

導(dǎo)航控制器push和pop 自定義轉(zhuǎn)場

1穴豫、略...同上
2凡简、略... 同上
3逼友、在push動畫之前設(shè)置導(dǎo)航控制器的轉(zhuǎn)場動畫代理,轉(zhuǎn)場時最上層的視圖控制器需要遵循<UINavigationControllerDelegate>的協(xié)議秤涩,并設(shè)置為代理帜乞,并實現(xiàn)如下代理方法:

 //在push動畫之前設(shè)置轉(zhuǎn)場動畫代理
 self.navigationController.delegate = animationFour;

#pragma mark -- UINavigationControllerDelegate
//返回處理push/pop動畫過渡的對象
- (nullable id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
                                            animationControllerForOperation:(UINavigationControllerOperation)operation
                                                         fromViewController:(UIViewController *)fromVC
                                                           toViewController:(UIViewController *)toVC{

    if (operation == UINavigationControllerOperationPush) {
        self.transitionAnimation.transitionType = WSLTransitionTwoTypePush;
        return self.transitionAnimation;
    }else if (operation == UINavigationControllerOperationPop){
        self.transitionAnimation.transitionType = WSLTransitionTwoTypePop;
    }
    return self.transitionAnimation;
}

//返回處理push/pop手勢過渡的對象 這個代理方法依賴于上方的方法 ,這個代理實際上是根據(jù)交互百分比來控制上方的動畫過程百分比
- (nullable id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
                                   interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>) animationController{

    //手勢開始的時候才需要傳入手勢過渡代理筐眷,如果直接pop或push黎烈,應(yīng)該返回nil,否者無法正常完成pop/push動作
    if ( self.transitionAnimation.transitionType == WSLTransitionTwoTypePop) {
        return self.transitionInteractive.isInteractive == YES ? self.transitionInteractive : nil;
    }
    return nil;
}

全屏側(cè)滑返回

創(chuàng)建一個繼承于UINavigationController的一個對象WSLNavigatioController匀谣,遵守協(xié)議<UIGestureRecognizerDelegate>,實現(xiàn)如下方法:

  // 獲取系統(tǒng)自帶滑動手勢的target對象
    id target = self.interactivePopGestureRecognizer.delegate;
    // 創(chuàng)建全屏滑動手勢照棋,調(diào)用系統(tǒng)自帶滑動手勢的target的action方法
    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:target action:@selector(handleNavigationTransition:)];
    // 設(shè)置手勢代理,攔截手勢觸發(fā)
    pan.delegate = self;
    // 給導(dǎo)航控制器的view添加全屏滑動手勢
    [self.view addGestureRecognizer:pan];
    // 禁止使用系統(tǒng)自帶的滑動手勢
    self.interactivePopGestureRecognizer.enabled = NO;

#pragma mark -- UIGestureRecognizerDelegate
// 什么時候調(diào)用:每次觸發(fā)手勢之前都會詢問下代理武翎,是否觸發(fā)烈炭。
// 作用:攔截手勢觸發(fā)
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
    // 注意:只有非根控制器才有滑動返回功能,根控制器沒有后频。
    // 判斷導(dǎo)航控制器是否只有一個子控制器梳庆,如果只有一個子控制器暖途,肯定是根控制器
    if (self.childViewControllers.count == 1) {
        // 表示用戶在根控制器界面卑惜,就不需要觸發(fā)滑動手勢,
        return NO;
    }
    return YES;
}

解決UIScrollView的滑動手勢與全屏側(cè)滑手勢的沖突

創(chuàng)建一個UIScrollView的類別UIScrollView+GestureConflict驻售,重寫如下方法:

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{

    // 首先判斷otherGestureRecognizer是不是系統(tǒng)pop手勢
    if ([otherGestureRecognizer.view isKindOfClass:NSClassFromString(@"UILayoutContainerView")]) {
        // 再判斷系統(tǒng)手勢的state是began還是fail露久,同時判斷scrollView的位置是不是正好在最左邊
        if (otherGestureRecognizer.state == UIGestureRecognizerStateBegan && self.contentOffset.x == 0) {
            return YES;
        }
    }
    return NO;
}

更新于 2018/8/17 iOS 全屏側(cè)滑手勢/UIScrollView/UISlider間滑動手勢沖突

image

推薦閱讀:
http://www.reibang.com/p/45434f73019e
http://www.cocoachina.com/ios/20150811/12897.html

</article>

鏈接:http://www.reibang.com/p/a9b1307b305b

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市欺栗,隨后出現(xiàn)的幾起案子毫痕,更是在濱河造成了極大的恐慌,老刑警劉巖迟几,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件消请,死亡現(xiàn)場離奇詭異,居然都是意外死亡类腮,警方通過查閱死者的電腦和手機臊泰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蚜枢,“玉大人缸逃,你說我怎么就攤上這事〕С椋” “怎么了需频?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長筷凤。 經(jīng)常有香客問我昭殉,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任挪丢,我火速辦了婚禮莽鸭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘吃靠。我一直安慰自己硫眨,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布巢块。 她就那樣靜靜地躺著礁阁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪族奢。 梳的紋絲不亂的頭發(fā)上姥闭,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天,我揣著相機與錄音越走,去河邊找鬼棚品。 笑死,一個胖子當(dāng)著我的面吹牛廊敌,可吹牛的內(nèi)容都是我干的铜跑。 我是一名探鬼主播,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼骡澈,長吁一口氣:“原來是場噩夢啊……” “哼锅纺!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起肋殴,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤囤锉,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后护锤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體官地,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年烙懦,在試婚紗的時候發(fā)現(xiàn)自己被綠了驱入。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡修陡,死狀恐怖沧侥,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情魄鸦,我是刑警寧澤宴杀,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站拾因,受9級特大地震影響旺罢,放射性物質(zhì)發(fā)生泄漏旷余。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一扁达、第九天 我趴在偏房一處隱蔽的房頂上張望正卧。 院中可真熱鬧,春花似錦跪解、人聲如沸炉旷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽窘行。三九已至,卻和暖如春图仓,著一層夾襖步出監(jiān)牢的瞬間罐盔,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工救崔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留惶看,地道東北人。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓六孵,卻偏偏與公主長得像纬黎,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子狸臣,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,871評論 2 354