In this tutorial, we’ll be developing an application that implements a search function over a TableView using UISearchController. We’ve done something similar in an Android Tutorial here.
在本教程中,我们将开发一个应用程序,该应用程序使用UISearchController在TableView上实现搜索功能。 我们在这里的Android教程中做了类似的事情。
UISearchController (UISearchController)
UISearchController contains a protocol UISearchResultsUpdating
which informs our ViewController class through the function given below whenever text in the UISearchBar is changed.
UISearchController包含协议UISearchResultsUpdating
它通过功能通知我们的ViewController类下面每当在文本的UISearchBar改变给出。
func updateSearchResults(for searchController: UISearchController)
func updateSearchResults(for searchController: UISearchController)
In the following application, we’ll use a TableViewController as the default view controller type and add a UISearchController at the top of it programmatically(UISearchController is not available in the Interface Builder). We’ll be using a TableViewCell of the style Subtitle which contains a title and a description in each row that would be populated using a Model class.
在以下应用程序中,我们将使用TableViewController作为默认的视图控制器类型,并以编程方式在其顶部添加一个UISearchController(UISearchController在Interface Builder中不可用)。 我们将使用Subtitle样式的TableViewCell,该样式在每行中包含一个标题和一个描述,并将使用Model类填充该描述。
iOS UISearchController示例项目结构 (iOS UISearchController Example Project Structure)
故事板 (Storyboard)
UISearchController示例代码 (UISearchController example code)
Create a new file Model.swift
that stores the data for each row.
创建一个新文件Model.swift
,该文件存储每一行的数据。
import Foundation
struct Model {
let movie : String
let genre : String
}
The ViewController.swift
source code is given below.
下面给出了ViewController.swift
源代码。
import UIKit
class ViewController: UITableViewController {
var models = [Model]()
var filteredModels = [Model]()
let searchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.tableView.tableFooterView = UIView()
setupSearchController()
models = [
Model(movie:"The Dark Night", genre:"Action"),
Model(movie:"The Avengers", genre:"Action"),
Model(movie:"Logan", genre:"Action"),
Model(movie:"Shutter Island", genre:"Thriller"),
Model(movie:"Inception", genre:"Thriller"),
Model(movie:"Titanic", genre:"Romance"),
Model(movie:"La la Land", genre:"Romance"),
Model(movie:"Gone with the Wind", genre:"Romance"),
Model(movie:"Godfather", genre:"Drama"),
Model(movie:"Moonlight", genre:"Drama")
]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let model: Model
if searchController.isActive && searchController.searchBar.text != "" {
model = filteredModels[indexPath.row]
} else {
model = models[indexPath.row]
}
cell.textLabel!.text = model.movie
cell.detailTextLabel!.text = model.genre
return cell
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searchController.isActive && searchController.searchBar.text != "" {
return filteredModels.count
}
return models.count
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func setupSearchController() {
definesPresentationContext = true
searchController.dimsBackgroundDuringPresentation = false
searchController.searchResultsUpdater = self
searchController.searchBar.barTintColor = UIColor(white: 0.9, alpha: 0.9)
searchController.searchBar.placeholder = "Search by movie name or genre"
searchController.hidesNavigationBarDuringPresentation = false
tableView.tableHeaderView = searchController.searchBar
}
func filterRowsForSearchedText(_ searchText: String) {
filteredModels = models.filter({( model : Model) -> Bool in
return model.movie.lowercased().contains(searchText.lowercased())||model.genre.lowercased().contains(searchText.lowercased())
})
tableView.reloadData()
}
}
extension ViewController: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
if let term = searchController.searchBar.text {
filterRowsForSearchedText(term)
}
}
}
Pheww! That’s a big code. Let’s understand this step by step.
ew! 那是一个很大的代码。 让我们逐步了解这一点。
- The ViewController class implements UITableViewController. So there’s no need to implement the Delegate and DataSource protocols separately ViewController类实现UITableViewController。 因此,无需分别实现Delegate和DataSource协议
- The models array would contain the data for all the rows. The filteredModels array would contain the data for the rows that match the searched term based on the condition we’d be setting models数组将包含所有行的数据。 根据我们要设置的条件, filteredModels数组将包含与搜索到的术语匹配的行的数据
- The line that initialises the UISearchController is:
let searchController = UISearchController(searchResultsController: nil)
By setting the
searchResultsController
to nil we state that the search results would be updated in the current TableViewController itself rather than a different View.通过将
searchResultsController
设置为nil,我们声明将在当前TableViewController本身而不是其他View中更新搜索结果。 - To get rid of the empty rows we call:
为了摆脱空行,我们称之为:self.tableView.tableFooterView = UIView()
-
- Let’s setup a few features on the SearchController.
func setupSearchController() { definesPresentationContext = true searchController.dimsBackgroundDuringPresentation = false searchController.searchResultsUpdater = self searchController.searchBar.barTintColor = UIColor(white: 0.9, alpha: 0.9) searchController.searchBar.placeholder = "Search by movie name or genre" searchController.hidesNavigationBarDuringPresentation = false tableView.tableHeaderView = searchController.searchBar }
By setting definesPresentationContext to true we ensure that the search controller is presented within the bounds of the original table view controller.
searchResultsUpdater
conforms to theUISearchResultsUpdating
protocol. Setting this makes sure that the updateSearchResults function present in the extension would be invoked everytime text in searchBar changes.
- 让我们在SearchController上设置一些功能。
通过将definePresentationContext设置为true,我们确保将搜索控制器显示在原始表视图控制器的范围内。
-
searchResultsUpdater
符合UISearchResultsUpdating
协议。 设置此选项可确保每次searchBar中的文本更改时,都会调用扩展中存在的updateSearchResults函数。
- Let’s setup a few features on the SearchController.
- The TableView
cellForRowAt
andnumberOfRowsInSection
display the relevant data from the filteredModels or models class if the searchBar has some text or not. 如果searchBar是否包含某些文本,则TableViewcellForRowAt
和numberOfRowsInSection
显示filteredModels或models类中的相关数据。 The
filerRowsForSearchedText
function is invoked every time text changes inside the methodupdateSearchResults
.func filterRowsForSearchedText(_ searchText: String) { filteredModels = models.filter({( model : Model) -> Bool in return model.movie.lowercased().contains(searchText.lowercased())||model.genre.lowercased().contains(searchText.lowercased()) }) tableView.reloadData() }
In the above function, we filtered the
models
array and copy only those elements intofilteredModels
which are a substring of themodels.movie
ormodels.genre
class.filerRowsForSearchedText
方法updateSearchResults
文本更改时,都会调用filerRowsForSearchedText
函数。在上面的函数,我们过滤
models
阵列和复制仅这些要素成filteredModels
它们是的一个子models.movie
或models.genre
类。- In the above code, the part inside the filter method has a different syntax. It’s called a
closure
.{( model : Model) -> Bool in return model.movie.lowercased().contains(searchText.lowercased())||model.genre.lowercased().contains(searchText.lowercased()) }
filter()
takes a closure of type(model: Model) -> Bool
and iterates over the entire array, returning only those elements that match the condition.closure
。filter()
采用类型为(model: Model) -> Bool
的闭包,并遍历整个数组,仅返回与条件匹配的那些元素。
什么是封包? (What are closures?)
Closures are sort of anonymous functions without the keyword func
. The in
keyword is used to separate the input parameters from the return part.
闭包是一种没有关键字func
的匿名函数。 in
关键字用于将输入参数与返回部分分开。
An example of closures is:
闭包的示例是:
var closureToAdd: (Int, Int) -> Int = { (a, b) in
return a + b
}
print(closureToAdd(10,5)) //prints 15
The input parameters are Int followed by -> and the return type again an Int.
输入参数为Int,后跟->,返回类型再次为Int。
We can call a closure similar to the way we call functions.
我们可以像调用函数一样调用闭包。
The output of the above application in action is below.
上面的应用程序的输出如下。
This brings an end to this tutorial. You can download the iOS UISearchController example project from the link given below.
本教程到此结束。 您可以从下面给出的链接下载iOS UISearchController示例项目。
Reference: Official Documentation
参考: 官方文档
翻译自: https://www.journaldev.com/14126/ios-uisearchcontroller-uitableview