iOS中防止误触返回键丢失输入内容的标准实现方案
iOS防止儿童误触返回键丢失输入内容的标准实现方案
嘿,这个需求我太熟悉了——做儿童向APP的时候,防误触简直是刚需,还要兼顾系统原生体验,不能让用户觉得别扭。给你分享一下苹果官方推荐的标准解决方案,分版本处理,完美解决你不想自定义图标、要保留系统样式的痛点:
一、iOS 16+ 官方原生API方案(最优解)
iOS 16之后苹果提供了专门的API来拦截导航栏返回按钮的点击,完全不需要自定义按钮,直接保留系统原生的返回箭头和样式:
class YourInputViewController: UIViewController { // 标记是否有未保存的输入内容 private var hasUnsavedChanges = false override func viewDidLoad() { super.viewDidLoad() // 处理侧滑返回手势 navigationController?.interactivePopGestureRecognizer?.delegate = self } // iOS 16+ 专属:拦截导航栏返回按钮点击 @available(iOS 16.0, *) override func shouldPopOnBackButton() -> Bool { guard hasUnsavedChanges else { // 没有未保存内容,直接允许返回 return true } // 弹出确认对话框 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) // 返回false,阻止系统默认的返回行为 return false } } // 处理侧滑返回手势的拦截 extension YourInputViewController: UIGestureRecognizerDelegate { func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { guard gestureRecognizer == navigationController?.interactivePopGestureRecognizer else { return true } guard hasUnsavedChanges else { return true } // 同样弹出确认对话框 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 false } }
这个方案完全保留了系统返回按钮的所有原生样式,包括箭头、文字(自动继承前一个页面的标题),同时完美拦截了两种返回方式(导航栏按钮点击+侧滑手势)。
二、iOS 16以下兼容方案
对于iOS 15及更早的版本,没有shouldPopOnBackButtonAPI,我们可以创建一个和系统样式完全一致的返回按钮,替换默认的leftBarButtonItem,同时拦截侧滑手势:
class YourInputViewController: UIViewController { private var hasUnsavedChanges = false override func viewDidLoad() { super.viewDidLoad() // 创建和系统返回按钮一致的自定义按钮 setupSystemStyleBackButton() // 处理侧滑返回手势 navigationController?.interactivePopGestureRecognizer?.delegate = self } private func setupSystemStyleBackButton() { // 使用系统原生的返回箭头图标 let backImage = UIImage(systemName: "chevron.left")?.withRenderingMode(.alwaysTemplate) let backButton = UIBarButtonItem( image: backImage, style: .plain, target: self, action: #selector(handleBackButtonTap) ) // 设置按钮文字,和系统逻辑一致(显示前一个页面的标题) if let previousVC = navigationController?.viewControllers.first { backButton.title = previousVC.title ?? "返回" } else { backButton.title = "返回" } // 匹配系统按钮的文字样式 backButton.setTitleTextAttributes([ NSAttributedString.Key.font: UIFont.systemFont(ofSize: 17), NSAttributedString.Key.foregroundColor: UIColor.systemBlue ], for: .normal) navigationItem.leftBarButtonItem = backButton } @objc private func handleBackButtonTap() { guard hasUnsavedChanges else { navigationController?.popViewController(animated: true) return } // 弹出确认对话框 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) } } // 同样处理侧滑返回手势 extension YourInputViewController: UIGestureRecognizerDelegate { func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { guard gestureRecognizer == navigationController?.interactivePopGestureRecognizer else { return true } guard hasUnsavedChanges else { return true } 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 false } }
这个方案通过UIImage(systemName: "chevron.left")获取系统原生的返回箭头,再匹配系统的文字样式,视觉上和原生返回按钮几乎没有区别,完全符合系统规范。
关键注意点
- 不要在
viewDidDisappear中处理:这个方法是视图已经开始消失时触发的,无法取消返回操作,必须在返回动作触发前拦截(比如按钮点击、手势开始时)。 - 同时处理两种返回方式:用户可能通过导航栏按钮点击或侧滑手势返回,两种情况都要拦截,避免遗漏。
内容的提问来源于stack exchange,提问作者Jules
相关产品推荐
相关产品推荐

