Swift — 在TableView使用UISearchController

Albert
8 min readNov 19, 2018

--

Search Bar 讓我們可以輸入關鍵字去搜尋資料。基本上 Search Bar 只是造型不太一樣的 Text Field,讓使用者輸入文字,而程式得到使用者輸入的字串後去篩選資料,再用 Table View 將資料呈現出來,也就是我們得到的搜尋結果。

一般來說,Search Bar 會由另一個 View Controller 來做處理,例如:搜尋倉庫的庫存時,會用表單 ( TableView ) 來呈現結果;搜尋賣場商品,會用表格 ( CollectionView ) 來做呈現。

另外,雖然元件庫中有「Search Bar and Search Display Controller」,但建議不要再去使用它。

在開始之前我們需要前製作業,先打開 Xcode 新增一個專案,先做出一個TableView,並導入一些資料,這裡我使用英文 a到 z 來做示範。

那我們中間的步驟先省略,以下是我們所做出來的 TableView 以及執行的結果,在這裡我已經先加入了 Navigation Controller,並使用 Large Title:

現在我們先在 TableView 上置入 SearchController:

var mySearchController: UISearchController?

並創立一個 function 來做 mySearchController 的設定:

func settingSearchController(){}

我們在這個 function 中加入以下程式碼:

mySearchController = UISearchContrller(searchResultsController: nil)
mySearchController.searchResultsUpdater = self
self.navigationItem.searchController = mySearchController

我們逐一來解釋以上三行程式碼:
第一行我們去實例化 UISearchController,而我們回傳 nil,代表我們搜尋的結果會顯示於我們正在搜尋的 ViewController 上。
第二行是告知 SearchController,究竟是哪一個物件會負責更新我們搜尋的結果。
第三行就是在 Navigation Bar 上加上 Search Bar。

接下來這個 function 裡面要來設定 Search Bar 的外觀設定,這個部分我放到最後再做,我們先來做功能的部分,也就是過濾。

SearchController 沒有提供過濾的功能,所以我們必須自己實作過濾內容的規則。第一步我們先宣告一個變數來儲存搜尋的結果:

var filterResult: [String] = []

接著我們建立一個過濾內容的 function:

func filterContent(for searchText: String){
searchResults = array.filter({ (filterArray) -> Bool in
let words = filterArray
let isMach = words.localizedCaseInsensitiveContains(searchText)
return isMath
})
}

在 Swift 中,filter 是用來過濾目前的 Array,只要符合 filter條件的 Array 項目,就會回傳 true;不符合的將會回傳 false,回傳 false 的項目就會被剃除。而我們使用 filter 搜尋,並回傳一個新的 Array,新的 Array 中都是放「符合」條件 ( 回傳 true )的項目。

localizedCaseInsensitiveContains 方法將會檢查 Array 內的項目是否包含搜尋文字,並且不區分英文大小寫。

以上我們已經實作了搜尋邏輯,接下來我們要將搜尋的結果更新到畫面上,首先我們要使用 UISearchResultsUpdating 協定:

class TableViewController: UITableViewController, UISearchResultsUpdating 

這個 protocol 定義了一個名叫 updateSearchResults(for:) 的 method,當使用者點 Search Bar 時,這個 method 就會被呼叫,我們插入以下程式:

func updateSearchResults(for searchController: UISearchController) {
if let searchText = searchController.searchBar.text {
filterContent(for: searchText)
tableView.reloadData()
}
}

當使用者在 Search Bar 輸入文字後,我們可以取得搜尋文字 (searchText),並將 searchText 傳給 filterContent(for:),最後我們重新載入Table View,所以我們最後呼叫 tableView.reloadData() 來載入使用者搜尋的結果。

還記得我們實例化 UISearchController 時是回傳 nil 嗎?TableViewController 現在負責顯示 Array 的內容及搜尋的結果,問題來了,要如何知道什麼時候顯示 Array 內容、什麼時候顯示搜尋結果呢?

App 在 Search Controller 啟動時才會顯示搜尋結果,而 Search Controller 提供了一個屬性,來驗證 Search Controller 是否被使用者點擊、使用。當使用者點擊 Search Bar,搜尋界面顯示時,isActive 屬性會設定為 true。

所以我們利用 isActive 這個屬性,來決定要讓 Table View Controller 顯示 Array 內容資料還是顯示搜尋結果。我們更變 TableView(_:numberOfRowsInSection:) 如下:

以及 TableView(_:cellForRowAt:):

當 mySearchController?.isActive 為 true 時,也就是 Search Controller 啟動時,results 將會存入 result[indexPath.row],也就是顯示搜尋結果;反之若回傳的 Bool 值為 false,result將會存入 array[indexPath.row]。

現在我們完成了 SearchController 的功能設定,最後我們要設定SearchController 的外觀設定。

在 settingSearchController() 中,我們插入一些屬性,這些屬性是比較常見的屬性:

・placeholder:在 search bar 沒有文字時,設定預設文字的屬性
・barTintColor:Search Bar 的背景色
・tintColor:設定 Search Bar 主要元素顏色的屬性。例如:遊標、Cancel

我們將這幾個屬性加入 settingSearchController() 中,再將

navigationItem.searchController = mySearchController

改為

tableView.tableHeaderView = mySearchCOntroller.searchBar

現在我們執行看看

--

--