利用 table view header 的 search bar 實現 iOS App 的搜尋功能
利用 search bar,我們可以快速在 iOS App 裡實現搜尋功能。接下來我們將示範在 table view 的 header 加上 search bar,利用它搜尋情歌王子劉德華的動人情歌。(ps: 為了簡化程式的難度,我們將重心放在本機端的搜尋,事先將劉德華歌單的 JSON 檔加到專案裡。)
加入 table view controller & navigation controller,將 table view controller 的類別設為繼承 UITableViewController 的 StoreItemListTableViewController
將 search bar 加到 table view header
方法1: 從 storyboard
將 search bar 拖曳到 table view 跟 cell 之間,讓 search bar 成為 table view 的 header。
方法2: 從程式
設定 table view 的 tableHeaderView。
class StoreItemListTableViewController: UITableViewController { func addSearchBar() {
let searchBar = UISearchBar(frame: CGRect(x: 0, y: 0, width: view.bounds.width, height: 44))
tableView.tableHeaderView = searchBar
} override func viewDidLoad() {
super.viewDidLoad()
addSearchBar()
}
設定 cell 畫面,搭配自訂的 cell 類別 ItemCell
設定 cell 的類別。
設定 cell 的 Reuse ID。
連結 cell 裡元件的 outlet。
class ItemCell: UITableViewCell { @IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var itemImageView: UIImageView!
將 iTunes 抓到的劉德華歌曲 JSON 放到 asset
從以下網址抓取情歌王子劉德華的歌曲 JSON。
https://itunes.apple.com/search?term=劉德華&media=music&country=TW
定義 JSON 對應的 Codable 型別,從 asset 讀取 JSON,利用 static 變數 data 儲存歌曲的 array
import UIKitstruct StoreItem: Codable {
let trackName: String
let artistName: String
var kind: String
var artworkUrl100: URL
}struct SearchResponse: Codable {
let results: [StoreItem]
}extension StoreItem {
static var data: [Self] {
if let data = NSDataAsset(name: "劉德華")?.data {
let decoder = JSONDecoder()
do {
let searchResponse = try decoder.decode(SearchResponse.self, from: data)
return searchResponse.results
} catch {
print(error)
}
}
return [] }
}
加入顯示圖片的套件 Kingfisher
在 cell 裡定義設定畫面的 function configure(item:)
import UIKit
import Kingfisherclass ItemCell: UITableViewCell { @IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var itemImageView: UIImageView!
func configure(item: StoreItem) {
nameLabel.text = item.trackName
itemImageView.kf.setImage(with: item.artworkUrl100, placeholder: UIImage(systemName: "music.note"))
}}
在 table view 顯示 StoreItem.data 儲存的歌曲 array
class StoreItemListTableViewController: UITableViewController { var items = StoreItem.data override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
} override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "\(ItemCell.self)", for: indexPath) as! ItemCell let item = items[indexPath.row]
cell.configure(item: item) return cell
}
執行 App
接下來終於進入我們的重頭戲了,我們想在鍵盤按下 search 鍵時顯示搜尋的結果,比方顯示劉德華歌名有愛的歌。
當使用者按下 search 鍵時,將觸發 search bar delegate 的 function searchBarSearchButtonClicked(_:)
,因此接下來我們必須先設定 search bar 的 delegate。
設定 search bar 的 delegate
將 table view controller 設為 search bar 的 delegate。
方法1: 從 storyboard
從 search bar 連線到 table view controller。
方法2: 從程式
class StoreItemListTableViewController: UITableViewController { func addSearchBar() {
let searchBar = UISearchBar(frame: CGRect(x: 0, y: 0, width: view.bounds.width, height: 44))
searchBar.delegate = self
tableView.tableHeaderView = searchBar
}
實作 table 顯示資料和 search 功能
import UIKitclass StoreItemListTableViewController: UITableViewController { var items = StoreItem.data
var filteredItems = [StoreItem]()
override func viewDidLoad() {
super.viewDidLoad()
filteredItems = items
} override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filteredItems.count
} override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "\(ItemCell.self)", for: indexPath) as! ItemCell let item = filteredItems[indexPath.row]
cell.configure(item: item) return cell
}
func search(_ searchTerm: String) {
if searchTerm.isEmpty {
filteredItems = items
} else {
filteredItems = items.filter {
$0.trackName.contains(searchTerm)
}
}
tableView.reloadData()
}}extension StoreItemListTableViewController: UISearchBarDelegate {
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
let searchTerm = searchBar.text ?? ""
search(searchTerm)
searchBar.resignFirstResponder()
}
}
說明
var filteredItems = [StoreItem]()
宣告儲存歌單的 filteredItems ,table view 改成顯示 filteredItems 的內容。
func search(_ searchTerm: String) {
if searchTerm.isEmpty {
filteredItems = items
} else {
filteredItems = items.filter {
$0.trackName.contains(searchTerm)
}
}
tableView.reloadData()
}
將 search 的功能寫在 function search(_:)
裡。當使用者沒有輸入 search 文字時,filteredItems 等於全部的歌單。當使用者輸入 search 文字時,filteredItems 等於包含 search 文字的歌單。
extension StoreItemListTableViewController: UISearchBarDelegate {
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
let searchTerm = searchBar.text ?? ""
search(searchTerm)
searchBar.resignFirstResponder()
}
}
使用者按下 search 鍵時,將觸發 search bar delegate 的 function searchBarSearchButtonClicked(_:)
,我們在 searchBarSearchButtonClicked(_:)
裡呼叫剛剛定義的 function search(_:)
進行搜尋,然後呼叫 searchBar 的 resignFirstResponder 收鍵盤。
執行 App,搜尋愛
範例的 GitHub 連結
串接網路 API 搜尋資料
剛剛的範例主要目的是介紹 search bar 的應用,因此我們簡化程式的難度,只做本機端的搜尋。如果想串接網路 API,利用 search bar 搜尋某個歌手的歌單,可進一步參考以下 Apple 官方的範例說明。