iOS-自定义模态跳转的运用

来源:互联网 发布:javaweb书籍推荐知乎 编辑:程序博客网 时间:2023/02/03 02:32

iOS开发中,常见界面之间的跳转方式有:

  • 1-改变window的根视图;
  • 2-模态跳转(present/dismiss);
  • 3-导航控制器的push(show)和pop.

但在实际开发中,以上三种界面跳转的方式无法满足我们的需求时,需要我们DIY,然后自定义模态跳转就起作用了.


下面通过写一个Demo来展示自定义模态跳转(Demo传送门在最后)

  • 利用UIPageViewController实现卡片是分页滚动
  • 自定义视图的模态跳转


1-present跳转核心代码

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {    // 容器视图    UIView *containerView = [transitionContext containerView];    // 当前控制器    UIViewController *fromVC = [transitionContext  viewControllerForKey:UITransitionContextFromViewControllerKey];    // 目标控制器    UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];    // 初始大小    CGRect initialFrame = self.originFrame;    // 最终大小    CGRect finalFrame = [transitionContext finalFrameForViewController:toVC];    // 目标控制器截屏(初始化之后的)    UIImageView *snapshot = [AnimationHelper getImage:toVC.view];    // 设置目标控制器的初始大小    snapshot.frame = initialFrame;    // 切圆角    snapshot.layer.cornerRadius = 25;    snapshot.layer.masksToBounds = YES;    // 添加到容器视图中    [containerView addSubview:toVC.view];    [containerView addSubview:snapshot];    // 隐藏目标控制器视图    toVC.view.hidden = YES;    // 设置动画属性    [AnimationHelper perspectiveTransformForContainerView:containerView];    // 默认让目标视图的截图 Y 轴 旋转180度    snapshot.layer.transform = [AnimationHelper yRotation:M_PI_2];    // 获取时间间隔    CGFloat duration = [self transitionDuration:transitionContext];    // 1 定义 关键帧动画    [UIView animateKeyframesWithDuration:duration delay:0 options:UIViewKeyframeAnimationOptionCalculationModeCubic animations:^{        // 2 添加关键帧动画1 - 让主控制器旋转 180 度        snapshot.layer.transform = [AnimationHelper yRotation:M_PI_2];        [UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:0.33 animations:^{            fromVC.view.layer.transform = [AnimationHelper yRotation:-M_PI_2];        }];        // 3 添加关键帧动画2 - 切换目标控制器的动画,让目标控制器截图旋转180度展示出来        [UIView addKeyframeWithRelativeStartTime:0.33 relativeDuration:0.33 animations:^{            snapshot.layer.transform = [AnimationHelper yRotation:0.0];        }];        // 4 添加关键帧动画3 - 设置目标控制器截屏的大小为最终屏幕        [UIView addKeyframeWithRelativeStartTime:0.66 relativeDuration:0.33 animations:^{            snapshot.frame = finalFrame;        }];    } completion:^(BOOL finished) {        // 显示目标控制器        toVC.view.hidden = NO;        // 恢复根控制器的 transform 为初始状态        fromVC.view.layer.transform = [AnimationHelper yRotation:0.0];        // 移除截屏        [snapshot removeFromSuperview];        // 完成 模态跳转动画        [transitionContext completeTransition:![transitionContext transitionWasCancelled]];    }];}

2-dismiss跳转核心代码

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {    // 容器视图    UIView *containerView = [transitionContext containerView];    // 当前控制器    UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];    // 目标控制器    UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];    // 最终大小    CGRect finialFrame = self.destinationFrame;    // 根控制器截屏(初始化之后的)    UIImageView *snapshot = [AnimationHelper getImage:fromVC.view];    // 切圆角    snapshot.layer.cornerRadius = 25;    snapshot.layer.masksToBounds = YES;    // 添加到容器视图中    [containerView addSubview:toVC.view];    [containerView addSubview:snapshot];    // 隐藏根控制器视图    fromVC.view.hidden = YES;    // 设置动画属性    [AnimationHelper perspectiveTransformForContainerView:containerView];    // 默认让目标视图的截图 Y 轴 旋转180度    toVC.view.layer.transform = [AnimationHelper yRotation:-M_PI_2];    // 获取时间间隔    CGFloat duration = [self transitionDuration:transitionContext];    // 1 定义 关键帧动画    [UIView animateKeyframesWithDuration:duration delay:0 options:UIViewKeyframeAnimationOptionCalculationModeCubic animations:^{        // 2 添加关键帧动画1 - 设置根控制器截屏的大小为最终大小        [UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:0.33 animations:^{            snapshot.frame = finialFrame;        }];        // 3 添加关键帧动画2 - 设置根控制器截屏旋转180度隐藏        [UIView addKeyframeWithRelativeStartTime:0.33 relativeDuration:0.33 animations:^{            snapshot.layer.transform = [AnimationHelper yRotation:M_PI_2];        }];        // 4 添加关键帧动画1 - 让目标控制器旋转 180 度 展示出来        [UIView addKeyframeWithRelativeStartTime:0.66 relativeDuration:0.33 animations:^{            toVC.view.layer.transform = [AnimationHelper yRotation:0.0];        }];    } completion:^(BOOL finished) {        // 显示目标控制器        fromVC.view.hidden = false;        // 移除截屏        [snapshot removeFromSuperview];        // 完成 模态跳转动画        [transitionContext completeTransition:![transitionContext transitionWasCancelled]];    }];}

3-跳需要模态跳转的控制器中接受代理

#pragma mark --------------------关键代码    // 设置模态跳转的代理方法    revealVC.transitioningDelegate = self;    // 设置需要手势的控制器    [self.swipeInteractionController wireToViewController:revealVC];#pragma mark --------------------关键代码    [self showViewController:revealVC sender:nil];

4-实现UIViewControllerTransitioningDelegate代理方法

- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {    self.flipPresentAnimationController.originFrame = self.cardView.frame;    return self.flipPresentAnimationController;}- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {    self.flipDismissAnimationController.destinationFrame = self.cardView.frame;    return self.flipDismissAnimationController;}- (id<UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id<UIViewControllerAnimatedTransitioning>)animator {    return self.swipeInteractionController.interactionInProgress ? self.swipeInteractionController : nil;}

Demo的传送门:

OC版地址

Swift版地址

0 0