iOS 17中自定义UIPresentationController被Tab Bar遮挡,是否改变其工作机制?
iOS17确实对UIPresentationController的呈现逻辑做了关键调整,结合Xcode15的编译行为,直接导致了你遇到的弹窗被TabBar遮挡问题:
核心变化
Xcode15编译的iOS17应用中,自定义模态弹窗的containerView默认会挂载到发起present操作的视图控制器的视图层级下,而非像iOS16及更早版本(或Xcode14编译的包)那样直接添加到UIWindow的全局根层级。
当你从TabBarController的子VC发起present时,弹窗容器会成为该子VC视图的子节点,而TabBar属于父级TabBarController的视图,z层级更高,自然会遮挡弹窗的安全区域部分。你尝试调整zPosition、前置containerView无效,是因为这些操作仅在当前子VC的视图层级内生效,无法突破父级TabBarController的视图层级限制。
可行解决方案
除了你目前使用的从TabBarController/UIWindow根VC发起present的方法,还有两种更灵活的修复方式:
1. 手动将containerView迁移到全局层级
重写自定义UIPresentationController的containerViewWillLayoutSubviews方法,把容器视图转移到UIWindow的根视图下:
class MyBottomSheetPresentationController: UIPresentationController { override func containerViewWillLayoutSubviews() { super.containerViewWillLayoutSubviews() guard let keyWindow = UIApplication.shared.windows.first(where: { $0.isKeyWindow }), let rootView = keyWindow.rootViewController?.view else { return } // 从原父视图移除,避免层级嵌套 containerView.removeFromSuperview() // 添加到全局根视图 rootView.addSubview(containerView) // 适配全屏 bounds(包含安全区) containerView.frame = rootView.bounds } }
注意:需要确保弹窗的生命周期管理正常,避免出现内存泄漏或视图状态异常。
2. 强制弹窗以全屏容器呈现
在自定义UIPresentationController中重写shouldPresentInFullscreen返回true,同时设置弹窗的modalPresentationCapturesStatusBarAppearance为true,让系统强制将弹窗容器挂载到全局层级:
// 自定义PresentationController class MyBottomSheetPresentationController: UIPresentationController { override var shouldPresentInFullscreen: Bool { return true } } // 转场代理中返回自定义PresentationController class MyBottomSheetTransitionDelegate: NSObject, UIViewControllerTransitioningDelegate { func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? { return MyBottomSheetPresentationController(presentedViewController: presented, presenting: presenting) } // 其他转场动画相关实现... } // 弹窗初始化时设置 let newVC = MyVCToPresent() newVC.modalPresentationStyle = .custom newVC.transitioningDelegate = MyBottomSheetTransitionDelegate() newVC.modalPresentationCapturesStatusBarAppearance = true
这种方法更符合iOS17的设计逻辑,无需手动调整层级,兼容性更好。
内容的提问来源于stack exchange,提问作者Xaxxus

