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

UIViewControllerTransitioningDelegate异常:present动画失效但dismiss正常

解决模态ViewController自定义转场动画的代理时机问题

问题分析

你遇到的核心问题是transitioningDelegate的赋值时机错误,导致UIKit无法正确读取自定义转场逻辑:

  • 在init()中设置:如果你的模态VC是通过Storyboard/XIB初始化的,init()方法根本不会被触发(此时调用的是init?(coder:)),代理完全没被设置,所以present动画无效果。
  • 在viewDidLoad()中设置:此时模态VC的present流程已经启动,UIKit已经用默认转场逻辑处理了present动画,只有dismiss时代理已生效,所以dismiss动画符合预期。

解决方案

正确的做法是在初始化模态VC之后、调用present(_:animated:completion:)之前,在外部设置它的transitioningDelegate,同时配置正确的模态展示样式:

  1. 外部提前设置代理
    在发起present的VC中执行以下逻辑:

    // 初始化模态VC(代码或Storyboard方式均可)
    let modalVC = YourModalViewController()
    // 关键步骤:在present前设置转场代理
    modalVC.transitioningDelegate = self
    // 必须设置为.custom,否则自定义转场会被忽略
    modalVC.modalPresentationStyle = .custom
    // 发起present操作
    present(modalVC, animated: true)
    
  2. 确保转场代理方法正确实现
    代理类(推荐用发起present的VC,也可复用模态VC自身)需要实现以下核心方法:

    extension YourPresentingViewController: UIViewControllerTransitioningDelegate {
        // 返回自定义present动画器
        func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            return CustomPresentAnimator() // 你的自定义present动画类
        }
        
        // 返回自定义dismiss动画器
        func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            return CustomDismissAnimator() // 你的自定义dismiss动画类
        }
        
        // 若需自定义overlay背景,返回自定义PresentationController
        func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
            return OverlayPresentationController(presentedViewController: presented, presenting: presenting)
        }
    }
    
  3. 修复overlayView的动画逻辑
    针对你需要的alpha过渡需求,在自定义OverlayPresentationController中处理:

    class OverlayPresentationController: UIPresentationController {
        private let overlayView = UIView()
        
        override init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?) {
            super.init(presentedViewController: presentedViewController, presenting: presentingViewController)
            overlayView.backgroundColor = .black
        }
        
        override func presentationTransitionWillBegin() {
            super.presentationTransitionWillBegin()
            overlayView.frame = containerView?.bounds ?? .zero
            overlayView.alpha = 0
            containerView?.addSubview(overlayView)
            
            // 配合转场协调器执行alpha动画
            presentedViewController.transitionCoordinator?.animate(alongsideTransition: { _ in
                self.overlayView.alpha = 0.65
            })
        }
        
        override func dismissalTransitionWillBegin() {
            super.dismissalTransitionWillBegin()
            // dismiss时反向过渡alpha
            presentedViewController.transitionCoordinator?.animate(alongsideTransition: { _ in
                self.overlayView.alpha = 0
            })
        }
    }
    

关键注意点

  • 绝对不要在模态VC内部的生命周期方法中设置transitioningDelegate,必须在present操作前完成赋值。
  • 自定义转场必须将modalPresentationStyle设为.custom,否则UIKit会直接使用默认转场逻辑。
  • 如果通过Storyboard实例化模态VC,要在instantiateViewController(withIdentifier:)之后立即设置代理和展示样式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 22:31:15