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

如何利用ViewWillDisappear取消视图消失并阻止NavigationController返回?

嘿,这个场景我太熟了!之前用viewWillDisappear确实踩过坑——等这个方法触发的时候,返回动作已经启动了,根本拦不住。给你几个实用的解决方案,按需选:

方案1:自定义导航栏返回按钮(最省心的可控方案)

直接替换系统默认的返回按钮,把点击逻辑完全握在自己手里。优点是简单粗暴,想怎么拦就怎么拦,缺点是需要自己调整按钮样式,尽量贴近系统风格。

override func viewDidLoad() {
    super.viewDidLoad()
    
    // 自定义返回按钮,样式可以根据需求调整
    let backButton = UIBarButtonItem(title: "返回", style: .plain, target: self, action: #selector(backButtonTapped))
    // 可选:设置按钮颜色和系统一致
    backButton.tintColor = .systemBlue
    navigationItem.leftBarButtonItem = backButton
}

@objc private func backButtonTapped() {
    // 这里写你的条件检查逻辑,比如判断是否有未保存内容
    guard !hasUnsavedChanges else {
        // 条件不满足,弹出提醒
        let alert = UIAlertController(title: "注意", message: "你的操作内容将不会保存,确定要返回吗?", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "取消", style: .cancel))
        alert.addAction(UIAlertAction(title: "确定返回", style: .destructive) { [weak self] _ in
            // 用户确认后再执行返回
            self?.navigationController?.popViewController(animated: true)
        })
        present(alert, animated: true)
        return
    }
    
    // 条件满足,直接返回
    navigationController?.popViewController(animated: true)
}

// 示例:模拟未保存状态的属性
private var hasUnsavedChanges: Bool {
    // 这里替换成你的实际检查逻辑
    return true
}
方案2:拦截系统返回+侧滑返回(用导航代理)

如果需要拦截系统默认返回按钮和侧滑返回手势,就用UINavigationControllerDelegate的方法。这个方案能覆盖所有返回场景,但要注意处理导航栈的状态,避免界面异常。

class YourViewController: UIViewController, UINavigationControllerDelegate {
    
    private var shouldPreventPop = false
    private var hasUnsavedChanges: Bool { true } // 替换为你的检查逻辑
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 设置当前VC为导航代理
        navigationController?.delegate = self
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        // 如果是被拦截的返回,重置状态
        if shouldPreventPop {
            shouldPreventPop = false
        } else {
            // 正常离开页面时,记得清空代理,避免循环引用
            navigationController?.delegate = nil
        }
    }
    
    func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
        // 判断是否是从当前页面返回上一页
        let isPoppingFromCurrentVC = navigationController.viewControllers.contains(self) && viewController != self
        
        guard isPoppingFromCurrentVC else { return }
        
        // 检查条件
        if hasUnsavedChanges {
            // 阻止默认返回动作:重置导航栈为只有当前VC
            shouldPreventPop = true
            navigationController.viewControllers = [self]
            
            // 弹出提醒框
            let alert = UIAlertController(title: "注意", message: "你的操作内容将不会保存,确定要返回吗?", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "取消", style: .cancel))
            alert.addAction(UIAlertAction(title: "确定返回", style: .destructive) { [weak self] _ in
                self?.navigationController?.popViewController(animated: true)
            })
            present(alert, animated: true)
        }
    }
}
方案3:iOS 13+ 模态场景专属拦截

如果你的页面是用present模态弹出的(不是导航栈push的),iOS13+可以用UIAdaptivePresentationControllerDelegate来拦截返回,这个方法更优雅:

class YourModalViewController: UIViewController, UIAdaptivePresentationControllerDelegate {
    
    private var hasUnsavedChanges: Bool { true } // 替换为你的检查逻辑
    
    override func viewDidLoad() {
        super.viewDidLoad()
        presentationController?.delegate = self
    }
    
    func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool {
        // 检查未保存状态
        guard !hasUnsavedChanges else {
            let alert = UIAlertController(title: "注意", message: "你的操作内容将不会保存,确定要返回吗?", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "取消", style: .cancel))
            alert.addAction(UIAlertAction(title: "确定返回", style: .destructive) { [weak self] _ in
                self?.dismiss(animated: true)
            })
            present(alert, animated: true)
            return false // 返回false阻止默认关闭
        }
        return true // 允许关闭
    }
}

总结一下

  • 只需要拦截点击返回:选方案1,简单可控
  • 需要拦截侧滑+系统返回:选方案2,覆盖所有场景
  • 模态弹出的页面:iOS13+用方案3更优雅

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:48:46