如何实现两个模态视图控制器的自定义转场动画:前滑下后淡入
你的思路完全可行!这种衔接式转场动画完美适配自定义转场方案
你的想法没问题——在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
相关产品推荐
相关产品推荐

