iOS自定義轉場動畫

NO IMAGE

iOS自定義轉場動畫

本文記錄分享下自定義轉場動畫的實現方法,具體到動畫效果:新浪微博圖集瀏覽轉場效果、手勢過渡動畫、網易音樂啟動屏轉場動畫、開關門動畫、全屏側滑返回效果 的代碼可以到Github WSLTransferAnimation下載查看,註釋還算清晰。

模態化present和dismiss 自定義轉場

1、創建一個遵循協議的動畫過渡管理對象,並實現如下兩個方法:

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

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

 //取出轉場前後視圖控制器上的視圖view
    UIView * toView = [transitionContext viewForKey:UITransitionContextToViewKey];
    UIView * fromView = [transitionContext viewForKey:UITransitionContextFromViewKey];

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

  //如果加入了手勢交互轉場,就需要根據手勢交互動作是否完成/取消來做操作,完成標記YES,取消標記NO,必須標記,否則系統認為還處於動畫過程中,會出現無法交互之類的bug
   [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
     if ([transitionContext transitionWasCancelled]) { 
    //如果取消轉場
          }else{
   //完成轉場
     }
}

2、自定義一個繼承於UIPercentDrivenInteractiveTransition的手勢過渡管理對象,可以根據手勢需要設置控制動畫轉場進度的百分比。

//必要調用實現的系統方法

//手勢過程中,通過updateInteractiveTransition設置轉場過程動畫進行的百分比,然後系統會根據百分比自動佈局動畫控件,不用我們控制了
 [self updateInteractiveTransition:percentComplete];
//完成轉場操作
 [self finishInteractiveTransition];
//取消轉場操作
 [self cancelInteractiveTransition];

3、轉場時最上層的視圖控制器需要遵循的協議,並設置為代理,並實現如下代理方法:

//設置轉場代理
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 自定義轉場

1、略…同上
2、略… 同上
3、在push動畫之前設置導航控制器的轉場動畫代理,轉場時最上層的視圖控制器需要遵循的協議,並設置為代理,並實現如下代理方法:

 //在push動畫之前設置轉場動畫代理
 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手勢過渡的對象 這個代理方法依賴於上方的方法 ,這個代理實際上是根據交互百分比來控制上方的動畫過程百分比
- (nullable id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
                                   interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>) animationController{
    
    //手勢開始的時候才需要傳入手勢過渡代理,如果直接pop或push,應該返回nil,否者無法正常完成pop/push動作
    if ( self.transitionAnimation.transitionType == WSLTransitionTwoTypePop) {
        return self.transitionInteractive.isInteractive == YES ? self.transitionInteractive : nil;
    }
    return nil;
}

全屏側滑返回

創建一個繼承於UINavigationController的一個對象WSLNavigatioController,遵守協議,實現如下方法:

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

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

解決UIScrollView的滑動手勢與全屏側滑手勢的衝突

創建一個UIScrollView的類別UIScrollView+GestureConflict,重寫如下方法:

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

更新於 2018/8/17 iOS 全屏側滑手勢/UIScrollView/UISlider間滑動手勢衝突

iOS自定義轉場動畫

相關文章

iOSUrlScheme實現APP間通信、分享

iOS瀑布流之柵格佈局

iOS瀑布流封裝

iOS仿系統指南針