UIKit:如何让UISheetPresentationController绑定当前页面,导航时隐藏
实现UISheetPresentationController与当前页面绑定的方案
核心思路
UISheetPresentationController是通过模态方式present在当前ViewController上的,默认会在导航push新页面时依然显示在顶层。要实现“与当前页面绑定、不干扰其他页面”的效果,核心是在当前页面离开导航栈顶部时隐藏sheet,返回时恢复显示状态。
具体实现步骤
1. 记录Sheet状态与引用
在当前ViewController中添加属性,用于跟踪sheet的显示状态和对应的ViewController引用:
class YourCurrentViewController: UIViewController { // 标记sheet是否处于显示状态 private var isSheetPresented = false // 弱引用sheet的ViewController,避免内存泄漏 private weak var sheetVC: UIViewController? // ...其他代码 }
2. 正确Present Sheet
在需要展示sheet的地方,配置并present,同时更新状态:
func showSheet() { let sheetVC = YourSheetContentViewController() sheetVC.modalPresentationStyle = .pageSheet // 配置sheet的样式(如高度、拖拽行为等) if let sheetPC = sheetVC.sheetPresentationController { sheetPC.detents = [.medium(), .large()] sheetPC.prefersGrabberVisible = true } present(sheetVC, animated: true) { [weak self] in self?.isSheetPresented = true self?.sheetVC = sheetVC } // 监听sheet自行dismiss的事件,更新状态 sheetVC.presentationController?.delegate = self }
3. 监听Sheet自行Dismiss
实现UIAdaptivePresentationControllerDelegate,处理sheet被用户手动关闭的情况:
extension YourCurrentViewController: UIAdaptivePresentationControllerDelegate { func presentationControllerDidDismiss(_ presentationController: UIPresentationController) { isSheetPresented = false sheetVC = nil } }
4. 导航切换时控制Sheet可见性
利用ViewController的生命周期方法,在页面离开/返回导航栈顶部时处理sheet:
override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) // 仅在当前页面被push出导航栈时处理 if isMovingFromParent, isSheetPresented { // 无动画关闭sheet,避免与导航动画冲突 dismiss(animated: false) { [weak self] in self?.isSheetPresented = true // 保留状态,用于返回时恢复 } } } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // 返回当前页面时,若之前sheet是显示状态则恢复 if isSheetPresented { showSheet() } }
最佳实践
- 状态独立存储:如果sheet需要保留用户输入状态(如表单内容),将状态存在当前ViewController中,而非sheet内部,恢复展示时直接赋值即可。
- 避免内存泄漏:始终用
weak引用sheet的ViewController,同时监听dismiss事件及时清空引用。 - 动画协调:导航切换时处理sheet用
animated: false,避免和系统导航动画产生冲突,保证流畅性。 - 代理解耦:如果当前页面是导航控制器的代理,也可以通过
navigationController(_:didShow:animated:)方法监听页面切换,实现相同逻辑,但生命周期方法更直接贴合页面绑定的需求。
内容的提问来源于stack exchange,提问作者Betul Aksu
相关产品推荐
相关产品推荐

