UISearchControllerはUINavigationItemと組み合わせて使うことしかできない(iOS)


概要

よく UINavigationItem と組み合わせて使われることが多い UISearchController ですが、これを単体のViewControllerとして使えないか検証してみました。

結論

UISearchControllerはUINavigationItemと組み合わせてしか使わないこと推奨です。

通常の使い方

navigationItem.searchControllerにUISearchControllerを割り当てるのが通常の使い方になるかと思います。

class ViewController: UIViewController {

    var searchController: UISearchController!

    override func viewDidLoad() {
        super.viewDidLoad()
        searchController = UISearchController(searchResultsController: TableViewController())
        searchController.showsSearchResultsController = true
        navigationItem.searchController = searchController
    }
}

独自のボタンでpresent

これを、Searchバーではなく、こちらで用意したボタンなどのアクションきっかけで表示したいと考えました。

present(searchController, animated: true)

このコードで表示をさせてみると、微妙に検索結果の上部に隙間が空いた検索表示になりました。

独自のボタンでpush

presentがダメなら、navigationのpushではどうだろうか。

navigationController?.pushViewController(searchController, animated: true)

このコードで表示をさせてみると、検索結果表示部だけ見えて、検索窓が見えない形になっています。

UISearchControllerのSearch Barを配置する

ドキュメントをよくみてみます。

On iOS, incorporate the search controller’s searchBar into your own view controller’s interface. Display your view controller in whatever way is appropriate for your app. See Displaying Searchable Content by Using a Search Controller and Using Suggested Searches with a Search Controller to learn how to implement a search controller in your app.

なるほど、searchBarをビューコントローラーに組み込む、とありますね。
今までのパターンはそのままUISearchControllerを無理矢理表示しようとしていたので、きちんとドキュメントに沿って、searchBarを配置してみましょう。

class ViewController: UIViewController {

    var searchController: UISearchController!

    override func viewDidLoad() {
        super.viewDidLoad()
        searchController = UISearchController(searchResultsController: TableViewController())
        searchController.showsSearchResultsController = true

        let searchBar = searchController.searchBar
        view.addSubview(searchBar)
        searchBar.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            searchBar.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
            searchBar.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
            searchBar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
        ])
    }
}

そうすると、検索バーをタップした瞬間、サーチバーが明後日の方向へ飛んで行きました。

まとめ

UISearchControllerはUINavigationItemと組み合わせて使われることしか想定されていないようです。
この場合、UIは検索窓の表示で画面が占有されてしまうので、例えば虫眼鏡ボタンを置いて、それを押下して検索させたい場合は自分でUISearchBarなどを組み合わせてUIを作成するのがよさそうです。

おまけ (tvOS)

tvOSの場合、そもそもUINavigationItemにsearchControllerのプロパティがありません。
UISearchContainerViewController と組み合わせて表示する形になります。

        let searchController = UISearchController(searchResultsController: TableViewController())
        let searchContainerViewController = UISearchContainerViewController(searchController: searchController)
        present(searchContainerViewController, animated: true, completion: nil)