init(searchResultsController:)方法初始化
UISearchController并传递第二个视图控制器,那么
UISearchController将在合适的时候显示该视图控制器。
UISearchBar对象,我们必须在初始化视图控制器的时候将
UISearchBar合并到用户界面。添加
s
earchBar
到包含我们需要被搜索内容的视图,当用户点击s
earchBar输入搜索内容,
UISearchController将自动显示搜索结果视图控制器并且通知APP搜索过程已经开始。
s
earchBar交互,
UISearchController将通知searchResultsUpdater属性对象,所以我们需要提供搜索结果更新对象(
searchResultsUpdater
),并且必须遵守
UISearchResultsUpdating协议。我们可以使用协议中的方法来操作搜索的内容并传递结果到搜索结果视图控制。很显然,视图控制器拥有可搜索的内容,所以当前视图控制器可以充当搜索结果更新对象(
searchResultsUpdater
),简单一点理解就是代理。当然也可以使用其它对象。
delegate
属性,delegate
对象必须遵守UISearchControllerDelegate协议,当
search controller变得活跃并且搜索结果视图控制被显示(present)或去除(dismiss),协议中的方法会接收通知。
UISearchContainerViewController对象,然后present该对象。
以上内容信息请看这里。
相关方法和属性内容
初始化搜索控制器
具体Demo,原文例子请看这里,整体功能效果图和解释如下:
class SearchViewController: UIViewController{
@IBOutlet weak var tableView: UITableView!
var dataArray = [String]() //存储文件内容
var filteredArray = [String]() //存储搜索结果数据
var shouldShowSearchResults = false //是否显示搜索结果
var searchController: UISearchController!
override func viewDidLoad() {
super.viewDidLoad()
configureSearchController()
loadListOfCountries()
}
func configureSearchController(){
//通过参数searchResultsController传nil来初始化UISearchController,意思是我们告诉search controller我们会用相同的视图控制器来展示我们的搜索结果,如果我们想要指定一个不同的view controller,那就会被替代为显示搜索结果。
searchController = UISearchController(searchResultsController: nil)
//设置代理,searchResultUpdater是UISearchController的一个属性,它的值必须实现UISearchResultsUpdating协议,这个协议让我们的类在UISearchBar文字改变时被通知到,我们之后会实现这个协议。
searchController.searchResultsUpdater = self
//默认情况下,UISearchController暗化前一个view,这在我们使用另一个view controller来显示结果时非常有用,但当前情况我们并不想暗化当前view,即设置开始搜索时背景是否显示
searchController.dimsBackgroundDuringPresentation = false
//设置默认显示内容
searchController.searchBar.placeholder = "Search here..."
//设置searchBar的代理
searchController.searchBar.delegate = self
//设置searchBar自适应大小
searchController.searchBar.sizeToFit()
//设置definesPresentationContext为true,我们保证在UISearchController在激活状态下用户push到下一个view controller之后search bar不会仍留在界面上。
searchController.definesPresentationContext = true
//将searchBar设置为tableview的头视图
tableView.tableHeaderView = searchController.searchBar
}
func loadListOfCountries(){
//获取文件的指定路径
let pathToFile = Bundle.main.path(forResource: "countries", ofType: "txt")
//判断路径是否存在
if let path = pathToFile{
do{
//加载文件变成字符串
let countriesString = try String(contentsOfFile: path, encoding: .utf8)
//将字符串变为数组
dataArray = countriesString.components(separatedBy: "\n")
//刷新列表
tableView.reloadData()
}catch{
print(error.localizedDescription)
}
}
}
}
扩展SearchViewController实现UITableViewDelegate,UITableViewDataSource两个协议,并根据shouldShowSearchResults属性控制对应类型数据的显示,如果为true,那么显示搜索结果,如果为false,显示原列表。
//扩展SearchViewController实现UITableViewDelegate,UITableViewDataSource两个协议,并控制数据的显示
extension SearchViewController:UITableViewDelegate,UITableViewDataSource{
//MARK: UITableView Delegate and Datasource functions
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if shouldShowSearchResults {//是否显示搜索结果
return filteredArray.count
}
return dataArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "idCell", for: indexPath)
if shouldShowSearchResults{
cell.textLabel?.text = filteredArray[indexPath.row]
}else{
cell.textLabel?.text = dataArray[indexPath.row]
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60.0
}
}
//扩展SearchViewController实现UISearchBarDelegate和UISearchResultsUpdating两个协议
extension SearchViewController:UISearchBarDelegate,UISearchResultsUpdating{
//开始进行文本编辑,设置显示搜索结果,刷新列表
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
shouldShowSearchResults = true
tableView.reloadData()
}
//点击Cancel按钮,设置不显示搜索结果并刷新列表
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
shouldShowSearchResults = false
tableView.reloadData()
}
//点击搜索按钮,触发该代理方法,如果已经显示搜索结果,那么直接去除键盘,否则刷新列表
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
if !shouldShowSearchResults{
shouldShowSearchResults = true
tableView.reloadData()
}
searchController.searchBar.resignFirstResponder()
}
//这个updateSearchResultsForSearchController(_:)方法是UISearchResultsUpdating中唯一一个我们必须实现的方法。当search bar 成为第一响应者,或者search bar中的内容被改变将触发该方法.不管用户输入还是删除search bar的text,UISearchController都会被通知到并执行上述方法。
func updateSearchResults(for searchController: UISearchController) {
let searchString = searchController.searchBar.text
//过滤数据源,存储匹配的数据
filteredArray = dataArray.filter({ (country) -> Bool in
let countryText: NSString = country as NSString
return (countryText.range(of: searchString!, options: .caseInsensitive).location) != NSNotFound
})
//刷新表格
tableView.reloadData()
}
}
自定义UISearchBar和UISearchController
下面自定义UISearchBar和UISearchController,实现的效果如下,功能跟之前一样:
首先看自定义UISearchBar,自定义UISearchBar,其实就是继承UISearchBar,然后根据需求实现相应的初始化方法,并获取UISearchBar中的UITextField,对UITextField进行相应的属性设置,也可以在Draw方法中进行相应的绘制操作。具体代码如下:
class CustomSearchBar: UISearchBar {
var preferredFont: UIFont!
var preferredTextColor: UIColor!
//实现自定义初始化构造器,设置大小,字体,文本颜色,样式等基本属性
init(frame: CGRect,font: UIFont, textColor: UIColor) {
super.init(frame: frame)
self.frame = frame
preferredFont = font
preferredTextColor = textColor
//设置为prominent样式并且需要设置isTranslucent为false,为了searchBar和earch field都不透明。
searchBarStyle = UISearchBarStyle.prominent
isTranslucent = false
//注意:search bar并不是一个单一的控件,它是textfield的一部分。相反,search bar有一个UIView类型的子视图,该子视图有两个非常重要的子视图,一个是search field是UITextField类型的子类,另一个是search field的背景view。我们可以使用如下操作,打印子视图内容:
print(subviews[0].subviews)
}
//自定义子视图必须实现该方法
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//建立一个辅助函数,获取search field在search bar子视图中的位置
func indexOfSearchFieldInSubviews() ->Int!{
var index: Int!
let searchBarView = subviews[0]
for i in 0..
//自定义协议
protocol CustomSearchControllerDelegate{
func didStartSearching()
func didTapOnSearchButton()
func didTapOnCancelButton()
func didChangeSearchText(searchText: String)
}
class CustomSearchController: UISearchController {
//拥有自定义CustomSearchBar和代理对象
var customSearchBar: CustomSearchBar!
var customDelegate: CustomSearchControllerDelegate!
//1:构造初始化方法
init(searchResultsController: UIViewController?,searchBarFrame: CGRect,searchBarFont: UIFont,searchBarTextColor: UIColor,searchBarTintColor: UIColor) {
super.init(searchResultsController: searchResultsController)
configureSearchBar(frame: searchBarFrame, font: searchBarFont, textColor: searchBarTextColor, bgColor: searchBarTintColor)
}
//2:实现两个必须实现的方法
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
//3:自定义方法对SearchBar进行设置
func configureSearchBar(frame: CGRect, font: UIFont, textColor: UIColor, bgColor: UIColor) {
//创建自定义SearchBar
customSearchBar = CustomSearchBar(frame: frame, font: font , textColor: textColor)
//设置SearchBar相应的属性内容
customSearchBar.barTintColor = bgColor
customSearchBar.tintColor = textColor
customSearchBar.showsBookmarkButton = false
customSearchBar.showsCancelButton = true
customSearchBar.delegate = self
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
extension CustomSearchController: UISearchBarDelegate{
//当开始编辑search field,使用代理执行相应的协议方法
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
customDelegate.didStartSearching()
}
//当搜索按钮被点击,触发方法,取消键盘
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
customSearchBar.resignFirstResponder()
customDelegate.didTapOnSearchButton()
}
//点击取消按钮
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
customSearchBar.resignFirstResponder()
customDelegate.didTapOnCancelButton()
}
//文本发生改变
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
customDelegate.didChangeSearchText(searchText: searchText)
}
}
最后就是在SearchViewController中将使用原生SearchController替换成为自定义SearchController,并且实现代理,在协议方法中控制与自定义searchBar的交互。替换部分代码如下,具体可以看代码。
func configureCustomSearchController(){
//创建自定义SearchController并设置相应的属性
customSearchController = CustomSearchController(searchResultsController: self, searchBarFrame: CGRect(x: 0.0, y: 0.0, width: tableView.frame.size.width, height: 50.0), searchBarFont: UIFont(name: "Futura", size: 16.0)!, searchBarTextColor: UIColor.orange, searchBarTintColor: UIColor.black)
customSearchController.customSearchBar.placeholder = "Search in this awesome bar..."
tableView.tableHeaderView = customSearchController.customSearchBar
customSearchController.customDelegate = self
customSearchController.customSearchBar.sizeToFit()
}
//MARK:自定义UISearchBarController部分
extension SearchViewController:CustomSearchControllerDelegate{
func didStartSearching() {
shouldShowSearchResults = true
tableView.reloadData()
}
func didTapOnSearchButton() {
if !shouldShowSearchResults{
shouldShowSearchResults = true
tableView.reloadData()
}
}
func didTapOnCancelButton() {
shouldShowSearchResults = false
tableView.reloadData()
}
func didChangeSearchText(searchText: String) {
//过滤数据源,存储匹配的数据
filteredArray = dataArray.filter({ (country) -> Bool in
let countryText: NSString = country as NSString
return (countryText.range(of: searchText, options: .caseInsensitive).location) != NSNotFound
})
//刷新表格
tableView.reloadData()
}
}