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;
    }
}

完成

点击此处下载源码

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 概述 这篇文章,我将讲述几种转场动画的自定义方式,并且每种方式附上一个示例,毕竟代码才是我们的语言,这样比较容易上...
    伯恩的遗产阅读 54,193评论 37 381
  • OC开发我们主要有以下三种自定义方法,供大家参考:Push & PopModalSegue 前两种大家都很熟悉,第...
    ScaryMonsterLyn阅读 1,712评论 1 3
  • 更新,更简单的自定义转场集成! 几句代码快速集成自定义转场效果+ 全手势驱动 写在前面 这两天闲下来好好的研究了一...
    wazrx阅读 74,003评论 84 583
  • 晚上照例打开微信订阅号,逐一临幸那些闪着红圈圈的公众号们...... 第一篇《低质量的婚姻,不如高质量的单身》 第...
    小白话虫阅读 105评论 0 0
  • 之前花过一段时间整理了设计模式的相关知识。很久没看了,这里简单回顾下。知识温故而知新,尤其是这种原则、思想类的知识...
    纸简书生阅读 455评论 0 0