[Swift]iOS11以降、遷移時にナビゲーションがカクツク問題に対処する

# 前書き
``iphone X``の対応をするにあたり、発生したバグだったのですが、、、
``iphone X``じゃなくても古い端末で``iOS11``にしていると発生したので思わずびっくり。

# 現象

以下、遷移時の挙動（個人のアプリではないのでスレスレで公開しています、すいません、、。）
![move.gif](https://qiita-image-store.s3.amazonaws.com/0/175242/1295cf8f-bed9-b007-5e71-882e610d9708.gif)
ナビゲーションバーの下に**隙間**ができているのが見えるだろうか。
行ったり来たりするたびに、その隙間部分が**カクついている**笑

## もしかして、、、safeArea？

``iphone X``に関してググると、だいたいこいつがヒットする。
- [iOS11のバグ修正を行うに当たって気になったレイアウト関連の変更点](https://qiita.com/iganin/items/afbadb2d2b052d7b9ee9)
- [iOS11 で UIScrollView の contentInsetがずれる問題](https://qiita.com/peka2/items/b6301a0c06cc13286296)

``ContentInsetAdjustmentBehavior``をいじればなんとかなるんじゃね！と思いきやダメでした、、、。
それもそのはず、前書きでも書きましたが、``iphone X``じゃなくても**古い端末でiOS11にしていると発生する**ので。

## 原因は何、、、？

結果からいうと、**ナビゲーションバーにデフォルトの領域（高さ）以上の要素を突っ込む**と起こります。
もっというと、ナビゲーションバーの``titleView``にセットすると起こります。

例

```swift
let searchBar = UISearchBar()
navigationItem.titleView = searchBar
```

上記のアニメーション挙動は、上のコードで発生しています。
これは憶測なのでなんとも言えませんが、``UISearchBar``の高さがデフォルトで決まっているので、そちらが優先されている模様です。

## 解決策

解決策が２つあったのでご紹介します（２つとも実際に確認済み）

### 方法①動的にconstraintを調整

動的に``constraint``を操作することで調整しています。

```swift
let searchBar = UISearchBar()

if #available(iOS 11.0, *) {
   searchBar.heightAnchor.constraint(equalToConstant: 44).isActive = true
}

navigationItem.titleView = searchBar
```

※44はナビゲーションのデフォルトの高さ

### 方法②UIViewをワンクッション挟む

直接セットせず、ラッパーとしてUIViewをワンクッション挟んでからセットします。
ワンクッション挟むUIViewの大きさを先に決めてそこに描画（addSubview）する方法です。

```swift
let searchBar = UISearchBar()

if #available(iOS 11.0, *) {
  let wrapperView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: view.bounds.width, height: 44))
  searchBar.frame = wrapperView.bounds
  wrapperView.addSubview(searchBar)

  navigationItem.titleView = wrapperView           
}
```

一応、分岐処理をしっかり書くと以下

```swift
navigationItem.titleView = {
  let searchBar = UISearchBar()

  if #available(iOS 11.0, *) {
    let wrapperView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: view.bounds.width, height: 44))
    searchBar.frame = wrapperView.bounds
    wrapperView.addSubview(searchBar)
    return wrapperView
                
  } else {
    return searchBar
                
  }
}()
```

※44はナビゲーションのデフォルトの高さ

### 注意点

どちらにも言えますが、高さを削ってしまうので、少し窮屈な見た目になってしまいます。

左：調整前 / 右：調整後
<img width="394" alt="スクリーンショット 2017-11-15 1.12.20.png" src="https://qiita-image-store.s3.amazonaws.com/0/175242/b14c143b-648b-0781-cb37-639ddf4ecc04.png">

### 結果
高さを調節することで、遷移先と同じ高さになり、結果としてカクツキがなくなっているはずです。
別途良い方法があればご教授いただきたいです。


# 余談
今回たまたま発見したのですが、
デバッグ時に、たまにView構造確認のために、Xcodeの以下の機能を使用しており、

<img width="314" alt="スクリーンショット 2017-11-15 0.19.51.png" src="https://qiita-image-store.s3.amazonaws.com/0/175242/31572e57-44b2-b4b1-f2c7-2fa03d41d98e.png">

Xcode9からちょっと**進化**してました！

![スクリーンショット 2017-11-13 18.06.54.png](https://qiita-image-store.s3.amazonaws.com/0/175242/5f984e5a-1842-1b35-967e-554d08d650b5.png)

余白部分とか、はみ出ている部分に**クラス名が表示される**ようになってました！
これで、原因不明の余白が出た際に視覚的にもわかり、作業が捗るかと思います！

良いXcodeライフを！

# 参考
[UISearchBar increases navigation bar height in iOS 11](https://stackoverflow.com/questions/46318022/uisearchbar-increases-navigation-bar-height-in-ios-11)
[Can't set titleView in the center of navigation bar because back button](https://stackoverflow.com/questions/28121388/cant-set-titleview-in-the-center-of-navigation-bar-because-back-button)