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

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版地址
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值