在使用app时,搜索一个列表的内容是非常常见的,例如苹果自带的联系人:
我们可以使用UISearchController来实现这个功能。
UISearchController的属性
我们先来看看UISearchController有哪些属性:
// 初始化器:如果要在同一个控制器中显示搜索结果,searchResultsController参数传入nil (建议传入一个新的控制器,原因下面会讲到)
public init(searchResultsController: UIViewController?)
// 负责更新searchResultsController的内容
weak open var searchResultsUpdater: UISearchResultsUpdating?
// 是否激活
open var isActive: Bool
// 代理
weak open var delegate: UISearchControllerDelegate?
// 显示的时候是否加上阴影效果,默认是true
open var dimsBackgroundDuringPresentation: Bool
// 模糊背景效果,默认是true
open var obscuresBackgroundDuringPresentation: Bool
// 显示的时候是否隐藏导航栏,默认是true
open var hidesNavigationBarDuringPresentation: Bool
// 访问searchResultsController
open var searchResultsController: UIViewController? { get }
// 可以使用searchBar的代理来跟踪文本变化和按钮的事件
open var searchBar: UISearchBar { get }
初始化并设置相关属性
在viewDidLoad
初始化:
private func setupSearchController() {
//这个是另外创建的一个控制器,用来显示搜索结果
searchResultController = SearchResultTableViewController(style: .plain)
searchController = UISearchController(searchResultsController: searchResultController)
// 需要实现UISearchResultsUpdating这个协议,才能更新搜索结果
searchController.searchResultsUpdater = self
searchController.delegate = self
searchController.searchBar.placeholder = "搜索"
tableView.tableHeaderView = searchController.searchBar
}
UISearchResultsUpdating协议
我们通过扩展来实现这个协议:
extension TableViewController: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
searchResults = [] // 每次更新结果之前,把之前的搜索结果清零
if let searchText = searchController.searchBar.text {
for str in dataSource {
if str.contains(searchText) {
searchResults.append(str)
}
}
}
searchResultController.dataSource = searchResults // 把搜索结果赋值给显示结果控制器的数据源
}
}
UISearchControllerDelegate
我们通过扩展来实现这个代理,各个方法在何时调用,方法名很明显能看到,不再赘述:
extension TableViewController: UISearchControllerDelegate {
func presentSearchController(_ searchController: UISearchController) {
print("presentSearchController")
}
func willPresentSearchController(_ searchController: UISearchController) {
print("willPresentSearchController")
}
func didPresentSearchController(_ searchController: UISearchController) {
print("didPresentSearchController")
}
func willDismissSearchController(_ searchController: UISearchController) {
print("willDismissSearchController")
}
func didDismissSearchController(_ searchController: UISearchController) {
print("didDismissSearchController")
}
}
显示结果的控制器
在数据源中使用didSet
属性观察者,在被赋值后,刷新tableView
:
var dataSource: [String]! {
didSet {
tableView.reloadData()
}
}
另外,在numberOfRowsInSection
方法中,要注意判断数据源是否为nil
,因为搜索控制器被激活后,用户还没有输入搜索文字,这时数据源为nil
:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard dataSource != nil else { return 0 }
return dataSource.count
}
为什么要在另外一个控制器显示搜索结果
如果直接使用同一个控制器显示结果,我们不能根据搜索文字的变化通过更改dimsBackgroundDuringPresentation
属性来选择是否加上阴影效果。这样会影响我们点击显示搜索结果的cell。但是用另外一个控制器就没有问题。
Demo地址 >>
如果文中有错误,请指出!我们共同学习,共同进步。谢谢!