You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现两个模态视图控制器的自定义转场动画:前滑下后淡入

你的思路完全可行!这种衔接式转场动画完美适配自定义转场方案

你的想法没问题——在modal1下滑退出的同时让modal2从后方淡入,用自定义转场就能流畅实现,不用依赖截图(直接操作两个控制器的视图更高效)。结合WWDC学到的内容,咱们一步步来落地:

核心实现步骤

1. 配置转场基础设置

首先要让负责present的控制器(比如你的modal1)遵守UIViewControllerTransitioningDelegate协议,同时把要present的modal2的模态呈现方式设为.custom——这是启用自定义转场的前提:

// 在modal1里准备present modal2的代码
let modal2 = Modal2ViewController()
modal2.modalPresentationStyle = .custom
modal2.transitioningDelegate = self // 让modal1作为代理
present(modal2, animated: true)

2. 创建自定义转场动画类

新建一个遵守UIViewControllerAnimatedTransitioning协议的类,这是实现动画逻辑的核心。我们要在这个类里同时处理modal1的下滑和modal2的淡入:

class SlideOutFadeInTransition: NSObject, UIViewControllerAnimatedTransitioning {
    // 定义动画时长
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return 0.5
    }
    
    // 核心动画逻辑
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        // 获取转场涉及的两个控制器
        guard let fromVC = transitionContext.viewController(forKey: .from), // 要退出的modal1
              let toVC = transitionContext.viewController(forKey: .to) else { // 要进入的modal2
            transitionContext.completeTransition(false)
            return
        }
        
        let containerView = transitionContext.containerView
        // 先把modal2的视图添加到转场容器,初始设为透明
        containerView.addSubview(toVC.view)
        toVC.view.frame = containerView.bounds
        toVC.view.alpha = 0
        
        // 执行并行动画:modal1下滑出屏幕,modal2同步淡入
        UIView.animate(withDuration: transitionDuration(using: transitionContext), 
                       delay: 0,
                       options: .curveEaseInOut,
                       animations: {
            fromVC.view.frame.origin.y = containerView.bounds.height // modal1滑到屏幕下方
            toVC.view.alpha = 1 // modal2完全显示
        }) { finished in
            // 动画结束后必须标记转场完成,避免内存泄漏
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
        }
    }
}

3. 实现代理方法返回动画类

在modal1的扩展里实现UIViewControllerTransitioningDelegate的方法,告诉系统用咱们自定义的动画来处理present过程:

extension Modal1ViewController: UIViewControllerTransitioningDelegate {
    func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return SlideOutFadeInTransition()
    }
}

额外优化建议

  • 如果modal1带有导航栏,记得在设置frame时考虑安全区域,可以用containerView.safeAreaLayoutGuide.layoutFrame来替代containerView.bounds,避免视图偏移。
  • 可以调整动画的options参数,比如用.curveEaseOut让modal1的下滑更自然,或者添加弹簧效果让动画更生动。
  • 如果需要处理转场取消的情况(比如用户中途打断动画),可以在动画完成的闭包里根据transitionContext.transitionWasCancelled来做相应的视图恢复操作。

内容的提问来源于stack exchange,提问作者JPC

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:45:05