能否调整TableView和SearchBar的代理方法执行顺序?
解决方案
你遇到的问题本质是系统响应链的执行顺序固定,无法直接修改两个系统代理的回调优先级,可通过以下方案解决:
方案1:延迟执行关闭逻辑(改动最小,推荐)
将searchBarTextDidEndEditing中的关闭table操作异步派发到主队列的下一个执行周期,确保当前runloop中已触发的didSelectRowAt优先执行完成,再执行关闭逻辑。用户不会感知到任何延迟,完全符合业务预期。
修改后的代码如下:
extension CustomSearchBar: UISearchBarDelegate { func searchBarTextDidEndEditing(_ searchBar: UISearchBar) { print("searchBarTextDidEndEditing") self.setShowsCancelButton(false, animated: true) // 异步派发到主队列,等待当前所有触摸回调执行完成后再关闭 DispatchQueue.main.async { [weak self] in guard let self = self else { return } self.closeTableView() } } }
方案2:新增状态标识位控制
新增属性标记用户是否正在点击下拉建议列表,仅当用户没有点击列表时才在失焦时关闭table。
实现步骤:
- 新增状态属性
private var isTappingSuggestionTable: Bool = false
- 监听table的触摸事件修改状态
// 可以给tableView添加手势识别,或者重写cell的触摸回调 override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { let tablePoint = self.convert(point, to: self.tableView) if self.tableView.bounds.contains(tablePoint) { isTappingSuggestionTable = true } return super.hitTest(point, with: event) }
- 修改失焦逻辑的判断
func searchBarTextDidEndEditing(_ searchBar: UISearchBar) { print("searchBarTextDidEndEditing") self.setShowsCancelButton(false, animated: true) guard !isTappingSuggestionTable else { isTappingSuggestionTable = false return } self.closeTableView() }
- 在
didSelectRowAt执行完后重置状态并关闭table。
方案3:失焦时校验点击区域
在searchBarTextDidEndEditing触发时,获取当前用户的点击坐标,转换到当前控件的坐标系内,判断点击位置是否落在下拉table的有效展示区域内,如果是则不执行关闭,否则关闭。
内容的提问来源于stack exchange,提问作者nastassia
相关产品推荐
相关产品推荐

