UISearchController 實作搜尋功能

Patty
9 min readAug 16, 2022

建立搜尋功能、客製化搜尋列操作時相關設定,以及取消按鈕的文字和執行的事件。

流程

  1. 建立搜尋列 UISearchController
override func viewDidLoad() {
super.viewDidLoad()
let searchController = UISearchController()
}

2. 搜尋列位置:導覽列或表頭

navigationItem.searchController = searchController // 導覽列tableView.tableHeaderView = searchController.searchBar // 表頭

3. 實現搜尋功能

  • 【搜尋結果】
    宣告新變數用以儲存篩選後的資料內容,tableView 以新變數來顯示內容
lazy var filteredSongs = songs // 新變數
  • 【搜尋功能 protocol:UISearchResultsUpdating
    - 委派:將 controller 設為 UISearchController 的 searchResultsUpdater
    searchController.searchResultsUpdater = self
    - 遵從:UISearchResultsUpdating 的 protocol
    - 定義:updateSearchResults function:依據搜尋文字調整資料且呼叫 tableView的 reloadDate 更新顯示表格內容
// MARK: UISearchResultsUpdating - search controller 更新表格內容
extension AddWorldClockTableViewController: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
if let searchText = searchController.searchBar.text,
searchText.isEmpty == false {
filteredZoneList = zoneList.filter({($0.cityNameByCN+$0.countryNameByCN).localizedStandardContains(searchText)})
} else {
filteredZoneList = zoneList
}
tableView.reloadData()
}
}

補充

【固定搜尋列於上方】:畫面捲動時不隱藏搜尋列

// 畫面捲動 search bar 不隱藏 navigationItem.hidesSearchBarWhenScrolling = false
navigationItem.hidesSearchBarWhenScrolling

【搜尋時導覽列不隱藏】
p.s. 預設為 true,當搜尋時導覽列則隱藏

searchController.hidesNavigationBarDuringPresentation = false

【取消按鈕】

  • 固定顯示取消按鈕
    p.s. 預設為 false,只有搜尋文字不為空白字串才會顯示「取消」
searchController.searchBar.showsCancelButton = true
  • 取消按鈕標題文字
    p.s. 預設為 Cancel
if let cancelButton = searchController.searchBar.value(forKey: "cancelButton") as? UIButton {
cancelButton.setTitle("取消", for: .normal)
}
  • 客製化執行取消按鈕的事件 protocol:UISearchBarDelegate
    p.s. 預設為點選取消則取消搜尋

    - 委派:searchController.searchBar.delegate = self
    - 遵從:UISearchBarDelegate
    - 定義: searchBarCancelButtonClicked

➪ 實作:按下取消按鈕後退出畫面

// MARK: UISearchBarDelegate - search bar 取消觸發
extension AddWorldClockTableViewController: UISearchBarDelegate {
func searchBarCancelButtonClicked(_ searchBar: UISearchBar){
dismiss(animated: true, completion: nil)
}
}

【完整程式碼】

let zoneList = Zone.data
lazy var filteredZoneList = zoneList // 搜尋結果
override func viewDidLoad() {
super.viewDidLoad()

let searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self // 實作搜尋
tableView.tableHeaderView = searchController.searchBar // 搜尋列位置:表頭
navigationItem.searchController = searchController // 搜尋列位置:導覽列
navigationItem.hidesSearchBarWhenScrolling = false // 畫面捲動 search bar 不隱藏
searchController.hidesNavigationBarDuringPresentation = false //搜尋時是否隱藏導覽列
// 取消按鈕
searchController.searchBar.delegate = self // 實作取消
searchController.automaticallyShowsCancelButton = false // 不顯示取消按鈕;預設為true,點選search bar才顯示
searchController.searchBar.showsCancelButton = true // 取消按鈕一直顯示;預設為 false
if let cancelButton = searchController.searchBar.value(forKey: "cancelButton") as? UIButton {
cancelButton.setTitle("取消", for: .normal)
}
}
// MARK: UISearchResultsUpdating - search controller 更新表格內容
extension AddWorldClockTableViewController: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
if let searchText = searchController.searchBar.text,
searchText.isEmpty == false {
filteredZoneList = zoneList.filter({($0.cityNameByCN+$0.countryNameByCN).localizedStandardContains(searchText)})
} else {
filteredZoneList = zoneList
}
tableView.reloadData()
}
}
// MARK: UISearchBarDelegate - search bar 取消觸發
extension AddWorldClockTableViewController: UISearchBarDelegate {
func searchBarCancelButtonClicked(_ searchBar: UISearchBar){
delegate?.addWorldClockTableViewControllerDidCancel(self)
dismiss(animated: true, completion: nil)
}
}

實作:仿時鐘 App 的世界時鐘分頁搜尋時區

畫面刻畫和時區參考 GitHub

--

--