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

# 概要

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

https://developer.apple.com/documentation/uikit/uisearchcontroller

# 結論

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

## 通常の使い方

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

```swift
class ViewController: UIViewController {
    
    var searchController: UISearchController!

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

![Mar-11-2021 16-15-29.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687960/639d2fae-0eb1-5e3a-975b-01eefc082d2d.gif)

## 独自のボタンでpresent

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

```swift
present(searchController, animated: true)
```

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

<img width="300" alt="present search bar" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687960/a0a36420-4458-a413-1c6b-b683c0953b2f.png">


## 独自のボタンでpush

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

```swift
navigationController?.pushViewController(searchController, animated: true)
```

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

<img width="300" alt="push search bar" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687960/0127cdf4-9013-2c2c-df86-406eee21b373.png">

## 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を配置してみましょう。

```swift
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),
        ])
    }
}

```

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

![Mar-11-2021 16-12-56.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687960/687d7d58-b65e-ea14-b0c2-ffc2e5f51f82.gif)

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

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

https://developer.apple.com/documentation/uikit/uisearchcontainerviewcontroller

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

![Simulator Screen Shot - Apple TV 4K (at 1080p) - 2021-03-11 at 16.45.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687960/4a4b2a33-6384-4d82-2d23-0f734467e72b.png)