翻譯:luowanglin
原文地址
概覽
這個(gè)Demo演示了表視圖控制器(UITableViewController)和搜索控制器(UISearchController),怎樣去創(chuàng)建一個(gè)管理和展示搜索內(nèi)容的用戶交互功能。通過創(chuàng)建一個(gè)自定義的表視圖控制器,同時(shí)這個(gè)表示圖控制器也充當(dāng)展示或搜索結(jié)果的內(nèi)容提供器,然后展示搜索內(nèi)容范圍內(nèi)的過濾結(jié)果。
這個(gè)Demo實(shí)現(xiàn)了可選的UIStateRestoring接口協(xié)議,官方推介實(shí)現(xiàn)該接口協(xié)議。當(dāng)app重啟動時(shí),可以通過視圖控制器類去保存搜索欄的活動狀態(tài),其中包括第一響應(yīng)狀態(tài)和搜索欄文本,可進(jìn)行數(shù)據(jù)的恢復(fù)。間接提升了更好的用戶體驗(yàn)。
override func viewDidLoad() {
super.viewDidLoad()
resultsTableController = ResultsTableController()
resultsTableController.tableView.delegate = self
searchController = UISearchController(searchResultsController: resultsTableController)
searchController.searchResultsUpdater = self
searchController.searchBar.autocapitalizationType = .none
if #available(iOS 11.0, *) {
// For iOS 11 and later, place the search bar in the navigation bar.
navigationItem.searchController = searchController
// Make the search bar always visible.
navigationItem.hidesSearchBarWhenScrolling = false
} else {
// For iOS 10 and earlier, place the search controller's search bar in the table view's header.
tableView.tableHeaderView = searchController.searchBar
}
searchController.delegate = self
searchController.dimsBackgroundDuringPresentation = false // The default is true.
searchController.searchBar.delegate = self // Monitor when the search button is tapped.
/** Search presents a view controller by applying normal view controller presentation semantics.
This means that the presentation moves up the view controller hierarchy until it finds the root
view controller or one that defines a presentation context.
*/
/** Specify that this view controller determines how the search controller is presented.
The search controller should be presented modally and match the physical size of this view controller.
*/
definesPresentationContext = true
}
創(chuàng)建一個(gè)搜索控制器
使用繼承至UITableViewController的MainTableViewController類去創(chuàng)建一個(gè)搜索控制器。ResultsTableController表視圖控制器用于展示搜索欄中過濾后的產(chǎn)品(Product)結(jié)果。
為了兼容iOS系統(tǒng)版本,MainTableViewController搜索控制器需要進(jìn)行系統(tǒng)版本的判斷,當(dāng)系統(tǒng)版本小于或等于iOS10時(shí),你可以通過替換tableview里面的header視圖,而在iOS11后的版本,你可以直接替換視圖控制器的導(dǎo)航欄(navigation bar)。
刷新搜索結(jié)果
這個(gè)例子使用了UISearchResultsUpdating協(xié)議以及謂語適配器NSComparisonPredicate,去過濾分組里可用的產(chǎn)品(product)搜索結(jié)果。謂語(NSComparisonPredicate)是一個(gè)正則匹配基類,通過相應(yīng)謂語查詢規(guī)則進(jìn)行查詢或過濾。搜索規(guī)則是基于搜索欄的使用類型,會結(jié)合產(chǎn)品名稱、年份以及價(jià)格。
通過在裁截輸入欄中關(guān)鍵字的開頭和結(jié)尾預(yù)前進(jìn)行搜索。然后搜索字符串通過NSComparisonPredicate類里的findMatches函數(shù)進(jìn)行搜索結(jié)果返回。這個(gè)搜索結(jié)果以列表的方式返回。
func updateSearchResults(for searchController: UISearchController) {
// Update the filtered array based on the search text.
let searchResults = products
// Strip out all the leading and trailing spaces.
let whitespaceCharacterSet = CharacterSet.whitespaces
let strippedString =
searchController.searchBar.text!.trimmingCharacters(in: whitespaceCharacterSet)
let searchItems = strippedString.components(separatedBy: " ") as [String]
// Build all the "AND" expressions for each value in searchString.
let andMatchPredicates: [NSPredicate] = searchItems.map { searchString in
findMatches(searchString: searchString)
}
// Match up the fields of the Product object.
let finalCompoundPredicate =
NSCompoundPredicate(andPredicateWithSubpredicates: andMatchPredicates)
let filteredResults = searchResults.filter { finalCompoundPredicate.evaluate(with: $0) }
// Apply the filtered results to the search results table.
if let resultsController = searchController.searchResultsController as? ResultsTableController {
resultsController.filteredProducts = filteredResults
resultsController.tableView.reloadData()
}
}