【Swift】Search Controllerの使い方。検索されたら検索結果用のビューコントローラーを呼び出す。(Swift 2.1、XCode 7.2)
2020年6月16日
Search Controllerとは
本記事ではSwiftで使える部品のUISearchController(以下、サーチコントローラー)について説明する。
Xcodeの部品リストにSearch Bar and Search Display Controllerというものがある。これはサーチコントローラーと同じような部品ではあるが、現在はDeprecated(非推奨)になっていて、代わりにサーチコントローラーを使うのが推奨されている。
サーチコントローラーとは、Search Bar(以下、サーチーバー)を持ち、検索時にデリゲートメソッドの呼び出しと結果表示用のビューコントローラーを表示する部品である。
なお、サーチコントローラーはXcodeの部品リストの中には無いのでソースコードで実装する必要がある(Xcode 7.2)。
サーチコントローラーを試す
サーチコントローラーを使ってテーブルのデータを検索するものを実装してみよう。
以降の手順を開始する前のXcodeプロジェクトをGitHubに置いたので、実装を試してみる人はご利用されたし。
⇒「テスト用プロジェクト」
事前準備では、テーブルビューに人気雑誌の一覧を表示するところまで実装している。これにサーチコントローラーを追加して、入力文字列を含む雑誌の一覧が表示される動きを実装する。
サーチコントローラーはサーチバーの文字列が変更されると、下図のように、結果表示用ビューコントローラーのデリゲートメソッドを呼び出し、画面に表示されているビューの上に結果表示用ビューコントローラーのビューを重ねる。
検索用と結果表示用のビューコントローラーは同じにできるので、今回は1つのビューコントローラーのテーブルビューを更新する方法で検索結果を表示する。
ViewController.swiftを以下のコードに変更する。
ViewDidLoadメソッドで、結果表示用のビューコントローラーに自分を設定するのと、テーブルビューのヘッダーにサーチコントローラーのサーチバーを登録している。
「検索文字列変更時の呼び出しメソッド」が呼ばれたら、検索文字列を含むデータを抽出して検索結果配列に格納している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
// // ViewController.swift // import UIKit class ViewController: UIViewController, UITableViewDataSource, UISearchResultsUpdating { @IBOutlet weak var testTableView: UITableView! var searchController = UISearchController(searchResultsController: nil) //データ let dataList = ["月刊コロコロコミック(小学館)", "コロコロイチバン!(小学館)", "最強ジャンプ(集英社)", "Vジャンプ(集英社)", "週刊少年サンデー(小学館)", "週刊少年マガジン(講談社)", "週刊少年ジャンプ(集英社)", "週刊少年チャンピオン(秋田書店)", "月刊少年マガジン(講談社)", "月刊少年チャンピオン(秋田書店)", "月刊少年ガンガン(スクウェア)", "月刊少年エース(KADOKAWA)", "月刊少年シリウス(講談社)", "週刊ヤングジャンプ(集英社)", "ビッグコミックスピリッツ(小学館)", "週刊ヤングマガジン(講談社)"] //検索結果配列 var searchResults = [String]() //最初からあるメソッド override func viewDidLoad() { super.viewDidLoad() //結果表示用のビューコントローラーに自分を設定する。 searchController.searchResultsUpdater = self //検索中にコンテンツをグレー表示にしない。 searchController.dimsBackgroundDuringPresentation = false //テーブルビューのヘッダーにサーチバーを設定する。 testTableView.tableHeaderView = searchController.searchBar } //データを返すメソッド func tableView(tableView:UITableView, cellForRowAtIndexPath indexPath:NSIndexPath) -> UITableViewCell { //セルを取得する。 let cell = tableView.dequeueReusableCellWithIdentifier("TestCell", forIndexPath:indexPath) as UITableViewCell if( searchController.searchBar.text != "" ) { cell.textLabel?.text = searchResults[indexPath.row] } else { cell.textLabel?.text = dataList[indexPath.row] } return cell } //データの個数を返すメソッド func tableView(tableView:UITableView, numberOfRowsInSection section:Int) -> Int { if( searchController.searchBar.text != "" ) { return searchResults.count } else { return dataList.count } } //検索文字列変更時の呼び出しメソッド func updateSearchResultsForSearchController(searchController: UISearchController) { //検索文字列を含むデータを検索結果配列に格納する。 searchResults = dataList.filter { data in return data.containsString(searchController.searchBar.text!) } //テーブルビューを再読み込みする。 testTableView.reloadData() } } |
以下は実際のプレイ動画。サーチコントローラーが持っているサーチバーは最初からキャンセルボタンや削除ボタンが実装されているので嬉しい。
結果表示用のビューコントローラーを使う
先ほどの実装だとサーチバーの記事とほとんど変わらないので、結果表示用のビューコントローラーを使ってビューの上にビューを重ねるものを実装してみよう。
メニューから「File」⇒「New」⇒「File…」を選択する。
テンプレートを選択する画面が表示されるので、「iOSのSource」⇒「Cocoa Touch Class」を選択する。
クラス名を入力する画面が表示されるので、Classに「TestViewController」、Subclass ofに「UIViewController」を入力し、Nextボタンを押す。
保存先を指定する画面が表示されるので、プロジェクトと同じ場所であることを確認し、Createボタンを押す。
TestViewController.swift(以下、検索結果用ビューコントローラー)を以下のコードに変更する。
「検索文字列変更時の呼び出しメソッド」などの検索実行の処理をViewControllerクラスから検索結果用ビューコントローラーに移行した。検索結果用ビューコントローラーで新たにテーブルビューを作成し、検索結果をテーブルビューに表示している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
// // TestViewController.swift // import UIKit class TestViewController: UIViewController, UISearchResultsUpdating,UITableViewDelegate, UITableViewDataSource { //データ var dataList = [String]() //検索結果配列 var searchResults = [String]() //結果表示用テーブルビュー var tableView:UITableView! //最初からあるメソッド override func viewDidLoad() { super.viewDidLoad() //結果表示用のテーブルビューを作成する。 tableView = UITableView(frame:CGRectMake(100, 100, 200, 400)) tableView.registerClass(UITableViewCell.self,forCellReuseIdentifier: "TestCell") tableView.dataSource = self tableView.delegate = self self.view.addSubview(tableView) } //データの個数を返すメソッド func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return searchResults.count } //データを返すメソッド func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { //セルを取得する。 let cell = tableView.dequeueReusableCellWithIdentifier("TestCell", forIndexPath: indexPath) cell.textLabel!.text = searchResults[indexPath.row] return cell } //検索文字列変更時の呼び出しメソッド func updateSearchResultsForSearchController(searchController: UISearchController) { //検索文字列を含むデータを検索結果配列に格納する。 searchResults = dataList.filter { data in return data.containsString(searchController.searchBar.text!) } //テーブルビューを再読み込みする。 tableView.reloadData() } } |
ViewController.swiftを以下のコードに変更する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
// // ViewController.swift // import UIKit class ViewController: UIViewController, UITableViewDataSource { @IBOutlet weak var testTableView: UITableView! var searchController:UISearchController! //データ let dataList = ["月刊コロコロコミック(小学館)", "コロコロイチバン!(小学館)", "最強ジャンプ(集英社)", "Vジャンプ(集英社)", "週刊少年サンデー(小学館)", "週刊少年マガジン(講談社)", "週刊少年ジャンプ(集英社)", "週刊少年チャンピオン(秋田書店)", "月刊少年マガジン(講談社)", "月刊少年チャンピオン(秋田書店)", "月刊少年ガンガン(スクウェア)", "月刊少年エース(KADOKAWA)", "月刊少年シリウス(講談社)", "週刊ヤングジャンプ(集英社)", "ビッグコミックスピリッツ(小学館)", "週刊ヤングマガジン(講談社)"] //最初からあるメソッド override func viewDidLoad() { super.viewDidLoad() //結果表示用のビューコントローラーをサーチコントローラーに設定する。 let resultController = TestViewController() resultController.dataList = self.dataList searchController = UISearchController(searchResultsController: resultController) searchController.searchResultsUpdater = resultController //テーブルビューのヘッダーにサーチバーを設定する。 testTableView.tableHeaderView = searchController.searchBar } //データを返すメソッド func tableView(tableView:UITableView, cellForRowAtIndexPath indexPath:NSIndexPath) -> UITableViewCell { //セルを取得する。 let cell = tableView.dequeueReusableCellWithIdentifier("TestCell", forIndexPath:indexPath) as UITableViewCell cell.textLabel?.text = dataList[indexPath.row] return cell } //データの個数を返すメソッド func tableView(tableView:UITableView, numberOfRowsInSection section:Int) -> Int { return dataList.count } } |
以下は実際のプレイ動画。サーチバーに文字を入力すると最初からあるテーブルビューの上に検索結果のテーブルビューが表示される。
入力文字列をすべて消すかキャンセルボタンを押すまで検索結果のテーブルビューは表示され続け、その間は最初からあるテーブルビューをスクロールすることはできない。