Swift - 使用UISearchController实现带搜索栏的表格
(本文代码已升级至Swift3)
我原来写过一篇文章“Swift - 带结果列表的搜索条(UISearchDisplayController)的用法”,当时是使用UISearchDisplayController来实现带有搜索功能的列表,由于UISearchDisplayController本身就整合了搜索条和表格,所有用起来很方便。
我原来写过一篇文章“Swift - 带结果列表的搜索条(UISearchDisplayController)的用法”,当时是使用UISearchDisplayController来实现带有搜索功能的列表,由于UISearchDisplayController本身就整合了搜索条和表格,所有用起来很方便。
到了iOS8,苹果废除UISearchDisplayController,建议我们使用UISearchController配合UITableView来实现。我们可以把搜索条放在表格头部,或者放在页面顶部,还是很灵活的。下面通过代码演示如何使用UISearchController实现具有搜索功能的表格。
效果图如下:


样例代码说明:
(1)这里对ViewController做了类扩展ViewControllerExtensions.swift,把UITableView和UISearchController的代理方法都写在扩展类里,使代码更加简洁。
(2)同时这里提供两个样例。分别对应两种搜索方式,一个是实时搜索(即每输入一个字符就搜索过滤一次结果)。一个是输入时不进行搜索,只有点击键盘上的搜索按钮后才开始搜索。
一、实时搜索
--- ViewController.swift ---
import UIKit class ViewController: UIViewController { //展示列表 var tableView: UITableView! //搜索控制器 var countrySearchController = UISearchController() //原始数据集 let schoolArray = ["清华大学","北京大学","中国人民大学","北京交通大学","北京工业大学", "北京航空航天大学","北京理工大学","北京科技大学","中国政法大学", "中央财经大学","华北电力大学","北京体育大学","上海外国语大学","复旦大学", "华东师范大学","上海大学","河北工业大学"] //搜索过滤后的结果集 var searchArray:[String] = [String](){ didSet {self.tableView.reloadData()} } override func viewDidLoad() { super.viewDidLoad() //创建表视图 let tableViewFrame = CGRect(x: 0, y: 20, width: self.view.frame.width, height: self.view.frame.height-20) self.tableView = UITableView(frame: tableViewFrame, style:.plain) self.tableView!.delegate = self self.tableView!.dataSource = self //创建一个重用的单元格 self.tableView!.register(UITableViewCell.self, forCellReuseIdentifier: "MyCell") self.view.addSubview(self.tableView!) //配置搜索控制器 self.countrySearchController = ({ let controller = UISearchController(searchResultsController: nil) controller.searchResultsUpdater = self //两个样例使用不同的代理 controller.hidesNavigationBarDuringPresentation = false controller.dimsBackgroundDuringPresentation = false controller.searchBar.searchBarStyle = .minimal controller.searchBar.sizeToFit() self.tableView.tableHeaderView = controller.searchBar return controller })() } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(true) self.tableView.reloadData() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } }
--- ViewControllerExtensions.swift ---
import Foundation import UIKit extension ViewController: UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if self.countrySearchController.isActive { return self.searchArray.count } else { return self.schoolArray.count } } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { //为了提供表格显示性能,已创建完成的单元需重复使用 let identify:String = "MyCell" //同一形式的单元格重复使用,在声明时已注册 let cell = tableView.dequeueReusableCell(withIdentifier: identify, for: indexPath) if self.countrySearchController.isActive { cell.textLabel?.text = self.searchArray[indexPath.row] return cell } else { cell.textLabel?.text = self.schoolArray[indexPath.row] return cell } } } extension ViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) } } extension ViewController: UISearchResultsUpdating { //实时进行搜索 func updateSearchResults(for searchController: UISearchController) { self.searchArray = self.schoolArray.filter { (school) -> Bool in return school.contains(searchController.searchBar.text!) } } }
二、点击搜索按钮后才进行搜索
--- ViewController.swift ---
import UIKit class ViewController: UIViewController { //展示列表 var tableView: UITableView! //搜索控制器 var countrySearchController = UISearchController() //原始数据集 let schoolArray = ["清华大学","北京大学","中国人民大学","北京交通大学","北京工业大学", "北京航空航天大学","北京理工大学","北京科技大学","中国政法大学", "中央财经大学","华北电力大学","北京体育大学","上海外国语大学","复旦大学", "华东师范大学","上海大学","河北工业大学"] //搜索过滤后的结果集 var searchArray:[String] = [String](){ didSet {self.tableView.reloadData()} } override func viewDidLoad() { super.viewDidLoad() //创建表视图 let tableViewFrame = CGRect(x: 0, y: 20, width: self.view.frame.width, height: self.view.frame.height-20) self.tableView = UITableView(frame: tableViewFrame, style:.plain) self.tableView!.delegate = self self.tableView!.dataSource = self //创建一个重用的单元格 self.tableView!.register(UITableViewCell.self, forCellReuseIdentifier: "MyCell") self.view.addSubview(self.tableView!) //配置搜索控制器 self.countrySearchController = ({ let controller = UISearchController(searchResultsController: nil) controller.searchBar.delegate = self //两个样例使用不同的代理 controller.hidesNavigationBarDuringPresentation = false controller.dimsBackgroundDuringPresentation = false controller.searchBar.searchBarStyle = .minimal controller.searchBar.sizeToFit() self.tableView.tableHeaderView = controller.searchBar return controller })() } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(true) self.tableView.reloadData() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } }
--- ViewControllerExtensions.swift ---
import Foundation import UIKit extension ViewController: UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if self.countrySearchController.isActive { return self.searchArray.count } else { return self.schoolArray.count } } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { //为了提供表格显示性能,已创建完成的单元需重复使用 let identify:String = "MyCell" //同一形式的单元格重复使用,在声明时已注册 let cell = tableView.dequeueReusableCell(withIdentifier: identify, for: indexPath) if self.countrySearchController.isActive { cell.textLabel?.text = self.searchArray[indexPath.row] return cell } else { cell.textLabel?.text = self.schoolArray[indexPath.row] return cell } } } extension ViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) } } extension ViewController: UISearchBarDelegate { //点击搜索按钮 func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { self.searchArray = self.schoolArray.filter { (school) -> Bool in return school.contains(searchBar.text!) } } //点击取消按钮 func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { self.searchArray = self.schoolArray } }
你好,抱歉,我是新手入门。请问类拓展ViewControllerExtensions.swift是添加的那个文件。
你好,我想知道原始数据如果不是schoolArray 而是一个表的话应该怎么设置呢?
你好 可以把这个demo发我一份吗 2807338860@qq.com
你好 我添加这个的时候,报错
controller.searchResultsUpdater = self //两个样例使用不同的代理
运行时,编译到这里就闪退了
if self.countrySearchController.isActive
怎么解决
请问怎么取消实时搜索,改成通过点击键盘上的搜索按钮进行搜索。
您好
如果开启showsScopeBar,特别是将searchbar放到导航栏位置的话,显示会有问题,showsScopeBar整个被压在searchbar下面
再就是开启cancel按钮的话也会出现问题 最开始会显示 但如果点击搜索栏进入搜索模式后(搜索栏会自己弹出一个返回作用的cancel) 再返回去的话之前的cancel按钮就没有了
请问这两个问题有没有办法解决呢 谢谢
这样还不行,报如下错误
Connot invoke 'filter' with an argument lits of type '(@noescape(Element) throws -> Bool)'
语句为
self.requestSearch = self.requestData.filter(){$0.name.rangeOfString(searchController.searchBar.text!) != nil }
我的数据是这样的
let requestData = NSMutableArray()
requestData.addObject(TradeItem(name: "名称1", model: "款式", color: "颜色", size: "尺码"))
requestData.addObject(TradeItem(name: "名称2", model: "款式", color: "颜色", size: "尺码"))
requestData.addObject(TradeItem(name: "名称3", model: "款式", color: "颜色", size: "尺码"))
requestData.addObject(TradeItem(name: "名称4", model: "款式", color: "颜色", size: "尺码"))
requestData.addObject(TradeItem(name: "名称11", model: "款式", color: "颜色", size: "尺码"))
是定义的对象
搜索的内容 是一个对象 应该如何搜索?
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %@",
searchController.searchBar.text!)
let array = (self.schoolArray as NSArray)
.filteredArrayUsingPredicate(searchPredicate)
这段应该如何写》?
你理解错了
我要搜索框放在导航栏上
我的 ViewController 导航上加了UINavigationController 搜索框 没有在上面, 请问如何放上去?