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

如何在UIStoryboardSegue子类中插入源与目标视图间的中间视图?

解决UIStoryboardSegue中插入额外过渡视图的问题

嘿,这个问题我之前做自定义转场的时候也遇到过!其实你不用发愁找不到容器——苹果早就为这种场景准备了完美的解决方案:转场上下文的containerView。这正是专门用来承载转场过程中所有临时视图、源视图和目标视图的容器,完全能满足你插入额外视图的需求。

核心思路

转场时系统会创建一个UIViewControllerTransitioningContext对象,它的containerView属性就是我们要找的“视图容器”。你只需要把额外视图添加到这个容器里,就能和源视图、目标视图一起编排动画顺序了。

具体实现步骤

我给你写一个完整的示例,分两部分:自定义Segue子类 + 自定义动画控制器(用来精细控制三段动画)。

1. 创建自定义Segue子类

这个类负责触发转场,并关联我们的动画控制器:

import UIKit

class CustomThreeSlideSegue: UIStoryboardSegue {
    override func perform() {
        guard let sourceVC = source as? UIViewController,
              let destinationVC = destination as? UIViewController else {
            super.perform()
            return
        }
        
        // 设置目标控制器的转场代理为我们的动画控制器
        let animator = ThreeSlideAnimator()
        destinationVC.transitioningDelegate = animator
        // 如果是push转场,这里改成navigationController?.pushViewController(...)
        destinationVC.modalPresentationStyle = .fullScreen
        sourceVC.present(destinationVC, animated: true, completion: nil)
    }
}

2. 创建自定义动画控制器

这个类是核心,负责编排三段动画,并处理额外视图的添加和移除:

import UIKit

class ThreeSlideAnimator: NSObject, UIViewControllerAnimatedTransitioning, UIViewControllerTransitioningDelegate {
    // 实现转场代理方法,返回当前动画控制器
    func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return self
    }
    
    // 设置总动画时长,你可以根据需求调整
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return 1.8
    }
    
    // 核心动画逻辑
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        // 获取转场容器视图,这就是我们的载体!
        let containerView = transitionContext.containerView
        guard let sourceView = transitionContext.view(forKey: .from),
              let destinationView = transitionContext.view(forKey: .to) else {
            transitionContext.completeTransition(false)
            return
        }
        
        // 创建你的额外视图(这里用橙色视图做示例,你可以替换成设计师给的自定义视图)
        let extraView = UIView(frame: containerView.bounds)
        extraView.backgroundColor = .orange
        extraView.alpha = 1.0
        
        // 初始化视图位置:目标视图和额外视图先放在屏幕下方
        let screenHeight = containerView.bounds.height
        destinationView.frame = containerView.bounds.offsetBy(dx: 0, dy: screenHeight)
        extraView.frame = containerView.bounds.offsetBy(dx: 0, dy: screenHeight)
        
        // 按层级添加视图:源视图在最底层,然后是额外视图,最后是目标视图
        containerView.addSubview(sourceView)
        containerView.addSubview(extraView)
        containerView.addSubview(destinationView)
        
        // 拆分动画时长,三步各占1/3
        let stepDuration = transitionDuration(using: transitionContext) / 3
        
        // 第一步:源视图向上滑出屏幕
        UIView.animate(withDuration: stepDuration, animations: {
            sourceView.frame = containerView.bounds.offsetBy(dx: 0, dy: -screenHeight)
        }, completion: { _ in
            // 第二步:额外视图向上滑出屏幕
            UIView.animate(withDuration: stepDuration, animations: {
                extraView.frame = containerView.bounds.offsetBy(dx: 0, dy: -screenHeight)
            }, completion: { _ in
                // 第三步:目标视图向上滑入屏幕
                UIView.animate(withDuration: stepDuration, animations: {
                    destinationView.frame = containerView.bounds
                }, completion: { _ in
                    // 动画完成后,通知系统转场结束,并移除额外视图
                    transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
                    extraView.removeFromSuperview()
                })
            })
        })
    }
}

关键注意点

  • 视图层级顺序:一定要按“源视图 → 额外视图 → 目标视图”的顺序添加到containerView,否则动画过程中会出现视图遮挡问题。
  • 转场完成通知:必须调用transitionContext.completeTransition(),否则系统会认为转场未完成,可能导致控制器状态异常或内存泄漏。
  • 额外视图清理:转场完成后记得移除额外视图,避免它留在容器里占用资源。
  • 适配push转场:如果是导航栏的push/pop转场,只需要在Segue的perform()方法里替换成sourceVC.navigationController?.pushViewController(destinationVC, animated: true),动画控制器的逻辑基本不用改。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 12:11:44