如何在App进入sceneWillResignActive/后台时关闭UISheetPresentationController
解决App进入后台时关闭UISheetPresentationController的问题
当前点击齿轮图标会以UISheetPresentationController形式弹出SettingsViewController,同时App进入前台的sceneDidBecomeActive方法中会检查通知权限,若权限禁用则弹出UIAlertController。但如果此时SettingsViewController仍处于显示状态,会触发"already presenting"的报错,因此需要在App进入sceneWillResignActive或sceneDidEnterBackground时自动关闭该sheet。
方法一:通过SceneDelegate生命周期方法关闭
步骤1:在主ViewController中添加关闭逻辑
在弹出SettingsViewController的主控制器中,实现检查并关闭sheet的方法:
class ViewController: UIViewController { // ... 现有代码 ... func dismissSettingsSheetIfNeeded() { // 判断当前展示的是否是SettingsViewController if presentedViewController is SettingsViewController { dismiss(animated: false) // 非动画关闭,避免后台时的视觉异常 } } }
步骤2:在SceneDelegate中调用关闭方法
在SceneDelegate的sceneWillResignActive或sceneDidEnterBackground方法中,获取主控制器并执行关闭操作:
func sceneWillResignActive(_ scene: UIScene) { guard let windowScene = scene as? UIWindowScene, let rootNav = windowScene.windows.first?.rootViewController as? UINavigationController, let mainVC = rootNav.topViewController as? ViewController else { return } mainVC.dismissSettingsSheetIfNeeded() }
方法二:监听系统通知自动关闭
如果不想依赖SceneDelegate,可让主ViewController监听App状态变化通知:
步骤1:注册通知并实现关闭逻辑
在主ViewController的viewDidLoad中注册通知,同时编写关闭方法:
class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // 监听App即将失去活跃状态的通知 NotificationCenter.default.addObserver( self, selector: #selector(dismissSettingsSheet), name: UIApplication.willResignActiveNotification, object: nil ) // 也可监听进入后台的通知:UIApplication.didEnterBackgroundNotification } @objc private func dismissSettingsSheet() { if presentedViewController is SettingsViewController { dismiss(animated: false) } } deinit { // 移除通知观察者 NotificationCenter.default.removeObserver(self) } }
额外优化:保存SettingsViewController引用(可选)
如果需要更精确控制,可在弹出时保存SettingsViewController的引用,关闭时直接使用:
class ViewController: UIViewController { private var presentedSettingsVC: UIViewController? @IBAction func settings(_ sender: Any) { let storyboard = UIStoryboard(name: "Main", bundle: nil) let viewController = storyboard.instantiateViewController(withIdentifier: "SettingsViewController") if let presentationController = viewController.presentationController as? UISheetPresentationController { presentationController.detents = [.medium(), .large()] } present(viewController, animated: true) presentedSettingsVC = viewController // 保存引用 } @objc private func dismissSettingsSheet() { presentedSettingsVC?.dismiss(animated: false) presentedSettingsVC = nil // 清空引用 } }
通过以上任意一种方式处理后,App进入后台或即将失去活跃状态时,SettingsViewController会被自动关闭,回到前台时弹出UIAlertController就不会触发"already presenting"的错误。
内容的提问来源于stack exchange,提问作者Paul S.
相关产品推荐
相关产品推荐

