使用UISearchController时如何让导航栏按钮项始终显示
问题原因
UISearchController 激活时系统会默认接管导航栏展示,自动隐藏原 navigationItem 配置的按钮,仅展示搜索框相关控件,这是导致 Done、Cancel 按钮消失的核心原因。
解决方案
你只需要新增/调整以下两处配置即可让导航按钮始终显示:
- 首先禁用 UISearchController 对导航栏的默认接管行为,添加代码:
searchController.hidesNavigationBarDuringPresentation = false - 若需要兼容 iOS 15 及更低版本,额外实现 UISearchController 的代理回调,在搜索状态切换时重新赋值导航按钮即可:
// 首先遵循 UISearchControllerDelegate 协议 class TradeSelectionController: UITableViewController, UISearchResultsUpdating, UISearchBarDelegate, UISearchControllerDelegate { // ...原有代码 func searchBarSetup() { // ...原有配置 searchController.delegate = self // 新增代理绑定 searchController.hidesNavigationBarDuringPresentation = false // 新增这行 } // 新增两个代理方法 func willPresentSearchController(_ searchController: UISearchController) { resetNavigationBarButtons() } func willDismissSearchController(_ searchController: UISearchController) { resetNavigationBarButtons() } // 把导航按钮配置抽成公共方法 private func resetNavigationBarButtons() { self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneAction)) self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelAction)) } }
现有代码优化建议
- 避免使用隐式解包的
searchController : UISearchController!,改为直接初始化常量:let searchController = UISearchController(searchResultsController: nil),降低崩溃风险 - 当前
updateSearchResults方法中,搜索框失活就调用dismiss的逻辑不符合常规交互,用户仅取消搜索时不需要关闭当前页面,建议改为清空搜索关键字、重置列表数据源即可 - 不需要手动设置
searchController.searchBar.showsCancelButton = false,禁用导航栏接管后系统不会自动显示搜索框的取消按钮
完整修改后参考代码
import Foundation import UIKit class TradeSelectionController: UITableViewController, UISearchResultsUpdating, UISearchBarDelegate, UISearchControllerDelegate { let searchController = UISearchController(searchResultsController: nil) var isSearching = false // 可选:存储搜索关键字用于过滤数据源 var searchKeyword: String? = nil override func viewDidLoad() { super.viewDidLoad() addCancelBarItemWithBackButton(.present) setup() searchBarSetup() } func searchBarSetup() { tableView.allowsMultipleSelection = true tableView.estimatedRowHeight = tableView.rowHeight tableView.rowHeight = UITableView.automaticDimension searchController.searchResultsUpdater = self searchController.searchBar.delegate = self searchController.delegate = self searchController.obscuresBackgroundDuringPresentation = false searchController.hidesNavigationBarDuringPresentation = false searchController.searchBar.autocapitalizationType = .none navigationItem.searchController = searchController navigationItem.hidesSearchBarWhenScrolling = true // 初始设置导航按钮 resetNavigationBarButtons() } private func setup() { tableView.register(UITableViewCell.self, forCellReuseIdentifier: "TradeSelectionTableViewCell") tableView.separatorStyle = .none } private func resetNavigationBarButtons() { self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneAction)) self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelAction)) } func updateSearchResults(for searchController: UISearchController) { searchKeyword = searchController.searchBar.text isSearching = searchController.isActive // 这里替换为你自己的数据源过滤逻辑 tableView.reloadData() } func willPresentSearchController(_ searchController: UISearchController) { resetNavigationBarButtons() } func willDismissSearchController(_ searchController: UISearchController) { resetNavigationBarButtons() } @objc private func cancelAction(_ sender: Any?) { dismiss(animated: true, completion: nil) } @objc private func doneAction(_ sender: Any?) { dismiss(animated: true, completion: nil) } }
内容的提问来源于stack exchange,提问作者Pinal
相关产品推荐
相关产品推荐

