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

UIPresentationController底部弹窗取消保存后短暂全屏问题求助

解决自定义弹窗关闭“保存到文件”后短暂全屏的问题

嘿,这个坑我之前踩过!用UIPresentationController做底部自定义弹窗时,调用系统的“保存到文件”后确实会出现弹窗先闪全屏再恢复的情况,本质是系统处理模态转场时临时修改了presentedView的尺寸,而原来的布局逻辑没跟上。下面是我亲测有效的解决思路:

核心解决思路

  • 用约束替代直接设置Frame:别再只在containerViewWillLayoutSubviews()里硬写frame了,直接给presentedView添加明确的宽度、高度和位置约束,让系统无法随意修改它的尺寸。
  • 重写尺寸计算方法:在自定义的PresentationController里重写size(forChildContentContainer:withParentContainerSize:),返回你想要的弹窗尺寸,告诉系统这才是弹窗的理想大小。
  • 避免布局逻辑滞后:系统在关闭“保存到文件”视图后才触发containerViewWillLayoutSubviews(),这时候已经晚了,提前用约束和尺寸方法锁定布局,就能避免临时全屏的闪屏。

修改后的关键代码

自定义PresentationController

class SlideInPresentationController: UIPresentationController {
    private let direction: PresentationDirection
    private let disableCompactHeight: Bool
    
    init(presentedViewController: UIViewController,
         presenting presentingViewController: UIViewController?,
         direction: PresentationDirection,
         disableCompactHeight: Bool) {
        self.direction = direction
        self.disableCompactHeight = disableCompactHeight
        super.init(presentedViewController: presentedViewController, presenting: presentingViewController)
    }
    
    // 告诉系统弹窗的理想尺寸
    override func size(forChildContentContainer container: UIContentContainer, withParentContainerSize parentSize: CGSize) -> CGSize {
        // 根据你的需求返回自定义尺寸,比如高度300,宽度和父容器一致
        if disableCompactHeight && traitCollection.horizontalSizeClass == .compact && traitCollection.verticalSizeClass == .regular {
            return CGSize(width: parentSize.width, height: 300)
        }
        return super.size(forChildContentContainer: container, withParentContainerSize: parentSize)
    }
    
    override func containerViewWillLayoutSubviews() {
        super.containerViewWillLayoutSubviews()
        guard let presentedView = presentedView else { return }
        
        // 禁用自动转译,用约束控制布局
        presentedView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            presentedView.widthAnchor.constraint(equalTo: containerView!.widthAnchor),
            presentedView.heightAnchor.constraint(equalToConstant: 300), // 替换成你的弹窗高度
            presentedView.bottomAnchor.constraint(equalTo: containerView!.bottomAnchor) // 底部弹出的位置约束
        ])
    }
    
    // 可选:添加背景遮罩(如果需要的话)
    override func presentationTransitionWillBegin() {
        super.presentationTransitionWillBegin()
        let dimmingView = UIView()
        dimmingView.backgroundColor = UIColor.black.withAlphaComponent(0.5)
        dimmingView.frame = containerView!.bounds
        dimmingView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        containerView?.insertSubview(dimmingView, at: 0)
    }
}

确保TransitioningDelegate返回正确的PresentationController

class SlideInPresentationManager: NSObject, UIViewControllerTransitioningDelegate {
    var direction: PresentationDirection = .bottom
    var disableCompactHeight = true
    
    func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
        return SlideInPresentationController(presentedViewController: presented, presenting: presenting, direction: direction, disableCompactHeight: disableCompactHeight)
    }
}

为什么这样有效?

系统在处理“保存到文件”这种系统级模态视图时,会临时调整presentedView的尺寸来适配转场,但我们通过size(forChildContentContainer:)明确告诉了系统弹窗的理想尺寸,再加上约束锁定了位置和大小,系统就不会随便把弹窗拉成全屏了,关闭后也能保持正确的布局,不会出现闪屏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 03:51:21