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

完成

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值