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

自定義轉(zhuǎn)場動畫集錦.gif

本文記錄分享下自定義轉(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ù)手勢交互動作是否完成/取消來做操作,完成標記YES,取消標記NO,必須標記,否則系統(tǒng)認為還處于動畫過程中,會出現(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;
}

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

1、略...同上
2、略... 同上
3、在push動畫之前設(shè)置導航控制器的轉(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;
    // 給導航控制器的view添加全屏滑動手勢
    [self.view addGestureRecognizer:pan];
    // 禁止使用系統(tǒng)自帶的滑動手勢
    self.interactivePopGestureRecognizer.enabled = NO;

#pragma mark -- UIGestureRecognizerDelegate
// 什么時候調(diào)用:每次觸發(fā)手勢之前都會詢問下代理,是否觸發(fā)。
// 作用:攔截手勢觸發(fā)
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
    // 注意:只有非根控制器才有滑動返回功能,根控制器沒有。
    // 判斷導航控制器是否只有一個子控制器,如果只有一個子控制器,肯定是根控制器
    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間滑動手勢沖突

手勢沖突.gif

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 路漫漫其修遠兮,吾將上下而求索 前記 想研究自定義轉(zhuǎn)場動畫很久了,時間就像海綿,擠一擠還是有的,花了差不多有10天...
    半笑半醉間閱讀 7,659評論 10 51
  • iOS7.0后蘋果提供了自定義轉(zhuǎn)場動畫的API,利用這些API我們可以改變 push和pop(navigation...
    薛定喵的鵝閱讀 18,428評論 1 37
  • 更新,更簡單的自定義轉(zhuǎn)場集成! 幾句代碼快速集成自定義轉(zhuǎn)場效果+ 全手勢驅(qū)動 寫在前面 這兩天閑下來好好的研究了一...
    wazrx閱讀 74,213評論 84 583
  • iOS 7 以協(xié)議的方式開放了自定義轉(zhuǎn)場的 API,協(xié)議的好處是不再拘泥于具體的某個類,只要是遵守該協(xié)議的對象都能...
    iceMaple閱讀 2,089評論 0 13
  • 伊川王利珍堅持原創(chuàng)分享第66天 “不怕同學是學霸,就怕同學放暑假?!睓M批__差距越拉越大。這是姑娘班主任老師發(fā)給家...
    宛如初夏閱讀 344評論 1 2

友情鏈接更多精彩內(nèi)容