Large Titleを使いこなす3つの要点

#概要
iphoneアプリにおけるモダンなUIを実現するための方法として、**いかにApple公式アプリのUIをパクるか**は重要です。
iOS11にてAppleの公式UIとして[LargeTitle](https://developer.apple.com/design/human-interface-guidelines/ios/bars/navigation-bars/)というものが追加されました。
UINavigationBarが設定されたスクロールビューにてタイトルの位置と大きさをアニメーションでいい感じにしてくれます。
![music.gif](https://qiita-image-store.s3.amazonaws.com/0/179503/7e47ef41-9838-edd7-0f2e-075cd01cc3ae.gif)
**「ミュージック」におけるLargeTitle**

しかし、LargeTitleは周囲のUIパーツを正しく扱わないと残念な感じになってしまいます。
今回は実装に取り入れる上で、つまづいた**3つの点と解決策**をまとめました。

###記事の前提
- iOS11以降
- Master-Detail型の遷移（LargeTitleが設定されたScrollVIew→詳細ビュー）を伴うアプリ

#LargeTitleの実装
LargeTitleは簡単に以下の設定で有効にすることができます．

```swift:LargeTitle.swift
 //title設定
　　navigationItem.title = "title"

 //largeTitle表示
 navigationItem.largeTitleDisplayMode = .always
 navigationController?.navigationBar.prefersLargeTitles = true

 //laegeTitle(小)時の文字
 navigationController?.navigationBar.titleTextAttributes = [
     .foregroundColor: .white
 ]

 //laegeTitle(大)時の文字
 navigationController?.navigationBar.largeTitleTextAttributes = [
     .foregroundColor: .white,
     .font : UIFont.boldSystemFont(ofSize: 26.0)
 ]
```
具体的な実装は下記の記事にまとまっています
- [ios11からのNavigationBarを実装する(largeTitleDisplayMode)]
(https://qiita.com/tommy19970714/items/736d74ebb51daf276b2d)

##残念なLargeTitle
しかし、周囲のUIパーツを正しく扱わないと**下記**のような残念な感じになってしまいます．
![ex1.gif](https://qiita-image-store.s3.amazonaws.com/0/179503/fdd2a570-c273-08c1-ab39-b8b88d3951ee.gif)

具体的には以下の点がかっこ悪いです。
- LargeTitleとNavigationBarの間に残るボーダーライン
- ナビゲーションコントローラでの画面遷移時に黒い背景
- スクロール時にLargeTitleとNavigationBar間にどこかの背景色


#解決策

###LargeTitleとNavigationBarの間に残るボーダーライン
![IMG_8026.jpg](https://qiita-image-store.s3.amazonaws.com/0/179503/331fcee0-2b45-4150-a83c-cd7501923fca.jpeg)

LargeTitleが設定されている場合は大抵の場合無い方がキレイだと思いますが、デフォルトでは消してくれません。

これは、`navigationController.navigationBar.shadowImage`に設定されているUIImageです。

```swift:LargeTitle.swift
 //largeTitle時のnavigationBarのボーダを消す。戻す場合はnil代入
 navigationController?.navigationBar.shadowImage = UIImage()
```
また、nilが代入されるとデフォルトのボーダーラインに戻るようです。
画面遷移後もNavigationControllerのインスタンスは残るため、
1画面だけ消したい場合じゃDelegateメソッドなどでnilを代入し直す必要があります。

###ナビゲーションコントローラでの画面遷移時に黒い背景
![IMG_8027.jpg](https://qiita-image-store.s3.amazonaws.com/0/179503/5c57fc5e-0e50-8e59-7037-bdf406ca69a4.jpeg)

結論から言えばこいつは**NavigationController自身の持っているViewの色**です。
これについては情報が少なく、UIパーツ1つ1つの色を変えていくことでようやく発見しました。
そもそも**NavigationController自体がViewを持っている**という事実が完全に盲点、、、
下記のように、好きな色に変更することができます。遷移先のビューの色と合わせるときれいですね。

```swift:LargeTitle.swift
 //largetitleの適用時の画面遷移でチラ見する黒背景はコイツ
 navigationController.view.backgroundColor = .white
```

###スクロール時にLargeTitleとNavigationBar間にどこかの背景
<img width="284" alt="IMG_8034.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/179503/6678b19f-0621-f0b8-cdf0-5c94ddddf11d.jpeg">

LargeTitle設定時にスクロールをひっぱった際にどこかの背景が写ってしまいかっこ悪いです。
今回の実装ではCollectionViewを利用していたのですが、LargeTitleの変化アニメーションにひっぱられ、
なんと**CollectionViewの背景色のマイナス領域**が表示されていました。

CollectionViewに限らず、ScrollView上部とNavigationBarの色を揃えたい時はこの設定が必要です。ケースとしては特殊な例かも知れませんが、備忘録として書いておきます。

CollectionView自体の背景色は変えたくなかったため、
これは適当な高さのCALayerをマイナス領域にAddSublayerすることで解決しました。

```swift:LargeTitle.swift
//largetitleのスクロール時にcollectionviewの背景色が表示される現象対策
 let fillSpaceLayer = CALayer()
 fillSpaceLayer.backgroundColor = .white
 fillSpaceLayer.frame = CGRect(x:0, y:-100, width: self.view.frame.width, height: 100)
 collectionView.layer.addSublayer(fillSpaceLayer)
```

#まとめ
こんな感じにかっこよくLargeTitleを使いこなすことができました。
![result.gif](https://qiita-image-store.s3.amazonaws.com/0/179503/3515fb72-cff4-89c5-6eea-bfdd3c4073b4.gif)

```swift:LargeTitle.swift
 //largeTitle表示
 navigationItem.largeTitleDisplayMode = .always
 navigationController?.navigationBar.prefersLargeTitles = true
         
 //laegeTitle(小)時の文字色
 navigationController?.navigationBar.titleTextAttributes = [
     .foregroundColor: .white
 ]
 //laegeTitle(大)時の文字色
 navigationController?.navigationBar.largeTitleTextAttributes = [
     .foregroundColor: .white,
     .font : UIFont.boldSystemFont(ofSize: 26.0)
 ]
         
 //largeTitle時のnavigationBarのボーダを消す。戻す場合はnil代入
 avigationController?.navigationBar.shadowImage = UIImage()
         
 //largetitleの適用時の画面遷移でチラ見する黒背景はコイツ
 navigationController.view.backgroundColor = .white
         
 //largetitleのスクロール時にcollectionviewの背景色が表示される現象対策
 let fillSpaceLayer = CALayer()
 fillSpaceLayer.backgroundColor = .white
 fillSpaceLayer.frame = CGRect(x:0, y:-100, width: self.view.frame.width, height: 100)
 collectionView.layer.addSublayer(fillSpaceLayer)
```