如何阻止UISearchBarController取消按钮的点击事件传播?
解决UISearchBar取消按钮点击事件穿透到下方导航栏按钮的问题
这个问题我之前也遇到过!本质是事件穿透——搜索栏的取消按钮点击事件没有被完全消费,导致传递到了下层的Done按钮上。利用你提到的searchBarCancelButtonClicked(_:)代理方法就能完美解决,具体步骤如下:
1. 确保代理设置正确
首先,你的视图控制器需要遵守UISearchBarDelegate协议,并且将搜索栏的代理绑定到当前控制器:
class YourViewController: UIViewController, UISearchBarDelegate { override func viewDidLoad() { super.viewDidLoad() // 假设你的搜索栏实例是searchBar searchBar.delegate = self // 如果是用UISearchController,也可以这样绑定代理 // searchController.searchBar.delegate = self } }
2. 在代理方法中阻止事件传播
在searchBarCancelButtonClicked(_:)方法里,除了处理搜索栏的常规逻辑(收起键盘、关闭搜索控制器),还要添加代码阻止事件继续向下传递。这里有两种可靠的实现方式:
方式一:直接标记事件停止传播
通过获取当前的UI事件,标记它为已停止传播,这样事件就不会传递到下层的Done按钮:
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { // 1. 处理搜索栏的常规逻辑 searchBar.resignFirstResponder() // 收起键盘 searchBar.searchController?.dismiss(animated: true) // 关闭搜索控制器(如果需要) // 2. 阻止事件继续传播 if let currentEvent = UIApplication.shared.currentEvent { currentEvent.isPropagationStopped = true } }
方式二:用空动作消耗事件
如果第一种方式在某些iOS版本下不生效,可以用一个空方法来“消耗”当前事件,确保它不会继续传递:
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { // 1. 处理搜索栏的常规逻辑 searchBar.resignFirstResponder() searchBar.searchController?.dismiss(animated: true) // 2. 消耗事件,阻止传递 UIApplication.shared.sendAction(#selector(emptyAction), to: nil, from: self, for: nil) } // 空方法,用于消耗事件 @objc private func emptyAction() {}
额外排查点
如果还是存在问题,可以检查这两点:
- 确认Done按钮的点击事件绑定没有错误,比如是否不小心重复添加了点击手势;
- 如果使用
UISearchController,确保是通过navigationItem.searchController = searchController的方式集成,而不是手动添加到视图层级,这样系统会自动处理事件传递逻辑。
内容的提问来源于stack exchange,提问作者Trace
相关产品推荐
相关产品推荐

