Swift - 在表格头部添加一个带范围选择(scope bar)的搜索栏
(本文代码已升级至Swift3)
这次做个功能改进,就是在搜索条(searchBar)上增加一个范围选择(scopeBar),用户可以根据对应的分类更精确地筛选查询结果。
1,效果图
(1)通常状态下,表格头部只有一个搜索条。
(2)点击搜索条进入查询状态,同时顶部导航栏消失。输入条件后下方出现匹配的电影,默认查询全部。
(3)可以点击 scopeBar 上具体的分类来过滤结果,比如只显示“动画”类别下的查询结果。
2,样例代码
(1)Movie.swift(电影类)
import Foundation struct Movie{ //电影名 let name : String //类别 let category : String }
import UIKit class ViewController: UIViewController { //展示列表 var tableView: UITableView! //搜索控制器 var searchController = UISearchController(searchResultsController: nil) //电影集合 var movies = [Movie]() //搜索过滤后的结果集 var filteredMovies:[Movie] = [Movie](){ didSet {self.tableView.reloadData()} } override func viewDidLoad() { super.viewDidLoad() //初始化音乐集合 movies = [ Movie(name:"杀破狼", category:"动作"), Movie(name:"蝙蝠侠战超人", category:"动作"), Movie(name:"我的少女时代", category:"爱情"), Movie(name:"超能陆战队", category:"动画"), Movie(name:"西游记之大圣归来", category:"动画")] //创建表视图 self.tableView = UITableView(frame: self.view.frame, style:UITableViewStyle.plain) self.tableView!.delegate = self self.tableView!.dataSource = self self.view.addSubview(self.tableView!) //配置搜索控制器 searchController.searchResultsUpdater = self searchController.searchBar.delegate = self definesPresentationContext = true searchController.dimsBackgroundDuringPresentation = false //搜索状态下隐藏顶部导航栏 searchController.hidesNavigationBarDuringPresentation = true //配置分段条 searchController.searchBar.scopeButtonTitles = ["全部", "动作", "爱情", "动画"] tableView.tableHeaderView = searchController.searchBar } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(true) self.tableView.reloadData() } //根据条件过滤数据 func filterContentForSearchText(_ searchText: String, scope: String = "全部") { filteredMovies = movies.filter({( movie : Movie) -> Bool in let categoryMatch = (scope == "全部") || (movie.category == scope) return categoryMatch && movie.name.lowercased().contains( searchText.lowercased()) }) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } } extension ViewController: UITableViewDataSource { //返回表格行数 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if (self.searchController.isActive) { return self.filteredMovies.count } else { return self.movies.count } } //单元格内容设置 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = UITableViewCell(style: UITableViewCellStyle.subtitle, reuseIdentifier: "myCell") if (self.searchController.isActive) { cell.textLabel?.text = self.filteredMovies[indexPath.row].name cell.detailTextLabel?.text = self.filteredMovies[indexPath.row].category return cell } else { cell.textLabel?.text = self.movies[indexPath.row].name cell.detailTextLabel?.text = self.movies[indexPath.row].category return cell } } } extension ViewController: UITableViewDelegate{ //单元格选中事件 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) } } extension ViewController: UISearchBarDelegate { //范围分段条的选中项改变事件 func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) { filterContentForSearchText(searchBar.text!, scope: searchBar.scopeButtonTitles![selectedScope]) } } extension ViewController: UISearchResultsUpdating{ //搜索栏文字改变后事件 func updateSearchResults(for searchController: UISearchController) { let searchBar = searchController.searchBar let scope = searchBar.scopeButtonTitles![searchBar.selectedScopeButtonIndex] filterContentForSearchText(searchController.searchBar.text!, scope: scope) } }源码下载:hangge_1293.zip
功能改进
上面样例中,当我们点击搜索栏,如果不输入文字那么搜索结果都是空的。
如果我们需要在搜索框输入为空的情况下,将当前分类条目都显示出来,只需修改 filterContentForSearchText 这个方法即可。效果图如下:
//根据条件过滤数据 func filterContentForSearchText(_ searchText: String, scope: String = "全部") { filteredMovies = movies.filter({( movie : Movie) -> Bool in let categoryMatch = (scope == "全部") || (movie.category == scope) let textMarch = searchText == "" || movie.name.lowercased().contains( searchText.lowercased()) return categoryMatch && textMarch }) }
//根据条件过滤数据
func filterContentForSearchText(searchText: String, scope: String = "全部") {
filteredMovies = movies.filter({( movie: Movie) -> Bool in
let categoryMatch = (scope == "全部") || (movie.category == scope)
if categoryMatch {
if searchText == "" {
return categoryMatch
}else {
return movie.name.lowercased().contains(searchText.lowercased())
}
}
return categoryMatch && movie.name.lowercased().contains(searchText.lowercased())
})
}
这个方法需要这样优化一下,不然输入关键词点击分类无法显示类别数据
楼主太棒了。多谢。
感谢博主的代码示例……