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

UIModalTransitionStyle.coverVertical转场禁用蒙层变暗动画

解决方案

核心逻辑:弃用系统转场自带的蒙层渐变逻辑,将蒙层显示和模态窗上滑两个效果拆解开控制,蒙层直接瞬间添加不做动画,仅保留模态窗的上滑过渡。

快速实现(代码量少,适合快速修改)

直接在原有代码基础上调整,手动提前添加蒙层,自定义模态窗上滑动画,不需要引入额外的转场类:

if let subjectsListViewController = self.storyboard?.instantiateViewController(withIdentifier: "SubjectsListViewController") as? SubjectsListViewController {
    subjectsListViewController.delegate = self
    subjectsListViewController.modalPresentationStyle = .overCurrentContext
    subjectsListViewController.modalTransitionStyle = .crossDissolve
    
    // 1. 瞬间添加变暗蒙层,无任何过渡动画
    let dimmingView = UIView(frame: self.view.bounds)
    dimmingView.backgroundColor = .black.withAlphaComponent(0.4)
    dimmingView.tag = 999 // 用于dismiss时精准移除
    self.view.addSubview(dimmingView)
    
    // 2. 设置模态窗动画起始位置:屏幕底部外
    let screenHeight = UIScreen.main.bounds.height
    subjectsListViewController.view.transform = CGAffineTransform(translationX: 0, y: screenHeight)
    
    present(subjectsListViewController, animated: true, completion: nil)
    
    // 3. 仅执行模态窗上滑动画,时长与系统默认coverVertical一致
    UIView.animate(withDuration: 0.35, delay: 0, options: .curveEaseOut) {
        subjectsListViewController.view.transform = .identity
    }
}

注意:dismiss模态窗时,需要找到tag为999的蒙层手动移除,同时可以给模态窗加对应的下滑动画,和系统原生交互逻辑保持一致。

标准实现(推荐,稳定性高)

使用苹果官方推荐的UIPresentationController自定义转场逻辑,完全拆分蒙层和模态窗的动画,不需要手动管理视图生命周期,不会出现时序错乱问题:

  • 首先自定义PresentationController,单独管理蒙层,蒙层初始化时直接设置为最终可见状态,不添加渐变动画:
class InstantDimmingPresentationController: UIPresentationController {
    private lazy var dimmingView: UIView = {
        let view = UIView()
        view.backgroundColor = .black.withAlphaComponent(0.4)
        view.alpha = 1 // 直接设为最终透明度,不做渐变
        return view
    }()
    
    override func presentationTransitionWillBegin() {
        super.presentationTransitionWillBegin()
        guard let containerView = containerView else { return }
        dimmingView.frame = containerView.bounds
        containerView.insertSubview(dimmingView, at: 0)
    }
    
    override func dismissalTransitionWillBegin() {
        super.dismissalTransitionWillBegin()
        dimmingView.removeFromSuperview()
    }
    
    override var frameOfPresentedViewInContainerView: CGRect {
        containerView?.bounds ?? .zero
    }
}
  • 实现仅负责模态窗上滑的动画控制器,不处理任何蒙层逻辑:
class CoverVerticalOnlyAnimator: NSObject, UIViewControllerAnimatedTransitioning {
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        0.35 // 和系统默认coverVertical动画时长对齐
    }
    
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        guard let toView = transitionContext.view(forKey: .to) else {
            transitionContext.completeTransition(false)
            return
        }
        let containerView = transitionContext.containerView
        let screenHeight = UIScreen.main.bounds.height
        toView.frame = containerView.bounds
        toView.transform = CGAffineTransform(translationX: 0, y: screenHeight)
        containerView.addSubview(toView)
        
        UIView.animate(withDuration: transitionDuration(using: transitionContext), delay: 0, options: .curveEaseOut) {
            toView.transform = .identity
        } completion: { finished in
            transitionContext.completeTransition(finished)
        }
    }
}
  • 让弹出的模态控制器遵循UIViewControllerTransitioningDelegate,返回自定义的转场实例:
extension SubjectsListViewController: UIViewControllerTransitioningDelegate {
    func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
        InstantDimmingPresentationController(presentedViewController: presented, presenting: presenting)
    }
    
    func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        CoverVerticalOnlyAnimator()
    }
}
  • 调整原有present代码,使用自定义转场样式:
if let subjectsListViewController = self.storyboard?.instantiateViewController(withIdentifier: "SubjectsListViewController") as? SubjectsListViewController {
    subjectsListViewController.delegate = self
    subjectsListViewController.modalPresentationStyle = .custom
    subjectsListViewController.transitioningDelegate = subjectsListViewController
    present(subjectsListViewController, animated: true, completion: nil)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 06:18:17