iOS自定義轉場動畫(2)——自定義Pop轉場動畫并加入手勢驅動

自定義Pop轉場動畫

繼續使用上個程序,把push改為pop只需要做很少的工作就能完成

1、復制PushTransition.h和PushTransition.m。命名為PopTransition.h和PopTransition.m

2、在PopTransition.m中把

ViewController * fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
SecondViewController * toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

改為:

SecondViewController * fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
ViewController * toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

兩個類名交換位置即可

3、把所有的avatarImageView改為sourceImageView,把所有的sourceImageView改為avatarImageView,如下:

// 轉場動畫的具體內容
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext{
    // 獲取動畫的源控制器和目標控制器
    SecondViewController * fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    ViewController * toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    UIView * container = transitionContext.containerView;
    
    // 創建一個imageView的截圖,并把原本imageView隱藏,造成以為移動的就是imageView的假象
    UIView * snapshotView = [fromVC.avatarImageView snapshotViewAfterScreenUpdates:NO];
    snapshotView.frame = [container convertRect:fromVC.avatarImageView.frame fromView:fromVC.view];
    fromVC.avatarImageView.hidden = YES;
    
    // 設置目標控制器的位置,并把透明度設為0,在后面的動畫中慢慢顯示出來變為1
    toVC.view.frame = [transitionContext finalFrameForViewController:toVC];
    toVC.sourceImageView.hidden = YES;
    
    // 都添加到container中。注意順序
//    [container addSubview:toVC.view];
    [container insertSubview:toVC.view belowSubview:fromVC.view];
    [container addSubview:snapshotView];
    
    // 執行動畫
    [UIView animateKeyframesWithDuration:[self transitionDuration:transitionContext] delay:0 options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{
        snapshotView.frame = toVC.sourceImageView.frame;
        fromVC.view.alpha = 0;
    } completion:^(BOOL finished) {
        toVC.sourceImageView.hidden = NO;
        [snapshotView removeFromSuperview];
        fromVC.avatarImageView.hidden = NO;
        
        //一定要記得動畫完成后執行此方法,讓系統管理 navigation
        [transitionContext completeTransition: ![transitionContext transitionWasCancelled]]; // 如果參數寫成yes,當用戶取消pop時,會繼續執行動畫,也就是讓detailVC消失,設置成這個參數,會避免這樣的錯誤
    }];
}

4、修改ViewController中的判斷動畫類型的方法,加入pop的判斷:

- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC{
    if (operation == UINavigationControllerOperationPush){  // 就是在這里判斷是哪種動畫類型
        return [[PushTransition alloc] init]; // 返回push動畫的類
    }else if (operation == UINavigationControllerOperationPop){  // 就是在這里判斷是哪種動畫類型
        return [[PopTransition alloc] init]; // 返回pop動畫的類{
    }else{
        return nil;
    }
}

系統默認的 Push 和 Pop 動畫都支持手勢驅動,并且可以根據手勢移動距離改變動畫完成度。幸運的是,Cocoa 已經集成了相關方法,我們只用告訴它百分比就可以了。所以下一步就是手勢驅動。

1、在 SecondViewController 的 viewDidLoad() 方法中,加入滑動手勢。

    // 加入左側邊界手勢
    UIScreenEdgePanGestureRecognizer * edgePan = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(edgePanGesture:)];
    edgePan.edges = UIRectEdgeLeft;
    [self.view addGestureRecognizer:edgePan];

2、遵循UINavigationControllerDelegate協議,因為navigationController的動畫需要在這里執行,所以需要設置代理為自己

- (void)viewDidAppear:(BOOL)animated{
    [super viewDidAppear:animated];
    self.navigationController.delegate = self;
}

3、在手勢監聽方法中,創建 UIPercentDrivenInteractiveTransition 屬性,并實現手勢百分比更新。

// 在手勢監聽方法中,創建UIPercentDrivenInteractiveTransition屬性,并實現手勢百分比更新
- (void)edgePanGesture:(UIScreenEdgePanGestureRecognizer *)edgePan{
    // 進度值,這是左側邊界的算法,如果要改為右側邊界,改為self.view.bounds.size.width / [edgePan translationInView:self.view].x;
    CGFloat progress = [edgePan translationInView:self.view].x / self.view.bounds.size.width;
    if (edgePan.state == UIGestureRecognizerStateBegan) {
        self.percentDrivenTransition = [[UIPercentDrivenInteractiveTransition alloc] init];
        [self.navigationController popViewControllerAnimated:YES];
        
    }else if(edgePan.state == UIGestureRecognizerStateChanged){
        [self.percentDrivenTransition updateInteractiveTransition:progress];
    }else if(edgePan.state == UIGestureRecognizerStateCancelled || edgePan.state == UIGestureRecognizerStateEnded){
        if(progress > 0.5){
            [self.percentDrivenTransition finishInteractiveTransition];
        }else{
            [self.percentDrivenTransition cancelInteractiveTransition];
        }
        self.percentDrivenTransition = nil;
    }
}

4、實現返回 UIViewControllerInteractiveTransitioning 的方法并返回剛剛創建的 UIPercentDrivenInteractiveTransition屬性。

- (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController{
    if([animationController isKindOfClass:[PopTransition class]]){
        return self.percentDrivenTransition;
    }else{
        return nil;
    }
}

5、還需要設置一下返回動畫,否則手勢驅動不會生效

- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC{
    if (operation == UINavigationControllerOperationPop){
        return [[PopTransition alloc] init]; // 返回pop動畫的類
    }else{
        return nil;
    }
}

完成

點擊此處下載源碼

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • OC開發我們主要有以下三種自定義方法,供大家參考:Push & PopModalSegue 前兩種大家都很熟悉,第...
    ScaryMonsterLyn閱讀 1,682評論 1 3
  • 更新,更簡單的自定義轉場集成! 幾句代碼快速集成自定義轉場效果+ 全手勢驅動 寫在前面 這兩天閑下來好好的研究了一...
    wazrx閱讀 73,932評論 84 584
  • 晚上照例打開微信訂閱號,逐一臨幸那些閃著紅圈圈的公眾號們...... 第一篇《低質量的婚姻,不如高質量的單身》 第...
    小白話蟲閱讀 99評論 0 0
  • 之前花過一段時間整理了設計模式的相關知識。很久沒看了,這里簡單回顧下。知識溫故而知新,尤其是這種原則、思想類的知識...
    紙簡書生閱讀 436評論 0 0