iOS11のInsetsとLayout


# Insets

![views.png](https://qiita-image-store.s3.amazonaws.com/0/1380/470236a1-ae57-2749-7095-4a53994ad384.png)


半透明のナビゲーションバーやタブバーを配置して、下のテーブルの内容が潜り込んで見えるようにする場合、Insetsでその量を指定します。
iOS10の時は、「Adjust Scroll View Insets」にチェックを入れると、配置しているTableViewなどScrollView系のコンポーネントのContentInsetsが自動的に設定される仕組みになっていました。
![adjustInsets.png](https://qiita-image-store.s3.amazonaws.com/0/1380/212c7ee3-b9dd-6f33-7737-0fd4ea739e16.png)

iOS11からは、contentInsetsではなく、SafeAreaInsets → adjustedContentInset にその量が反映されるようになります。
「Adjust Scroll View Insets」(コードでは UIViewController.automaticallyAdjustsScrollViewInsets)はiOS11でdeprecatedになりました。

Viewのレイアウトも、iOS11でSafeAreaLayoutGuidesが追加され、UIViewControllerのtopLayoutGuide, bottomLayoutGuideがdeprecatedになりました。

Top/BottomLayoutGuideはUIViewControllerにありますが、SafeAreaLayoutGuidesはUIViewごとに存在します。
この「UIViewごとにある」というのがポイントで、Viewを複数重ねた中にある子Viewに対してもSafeAreaGuideの制約を作ることができるようになりました！


さらに、追加されたUIViewController.additionalSafeAreaInsetsで追加が可能。
タブバー/ナビバーを標準を使わず独自に作った時など...とかに使えそうです。

# iPhoneXのサイズ

![iPhoneXPortrait.png](https://qiita-image-store.s3.amazonaws.com/0/1380/7e35cea8-6915-c1ba-b604-2a5d5acf5747.png)

![iPhoneXLandscape.png](https://qiita-image-store.s3.amazonaws.com/0/1380/76c2fbf2-3029-43f3-2078-63ab35c9b9e9.png)

半透明なナビゲーションバー、タブバーを配置した時の各種サイズです。
ステータスバーが20→44ptに代わり、BottomにHomeIndicatorのエリアとして34pt追加されます。
端末を横にした時には左右のInsetsが44pt出てきます。

Table.layoutMarginの値は、「Preserve Superview Margins」がOFFの時の値です。

# iPhoneXのBottom部分に色を塗る3つの方法

![Screen Shot 2017-10-16 at 3.33.01.png](https://qiita-image-store.s3.amazonaws.com/0/1380/b6e43a34-f65e-5ffa-5ff1-4b3961eff01e.png)

こんな感じで色を塗りたい場合。

## 方法1

Align Bottom to: Safe Areaにして、UIViewController.view.backgroundColorを同じ色で塗る。
コレでいけるのであれば一番ラク。
![Screen Shot 2017-10-16 at 3.40.37.png](https://qiita-image-store.s3.amazonaws.com/0/1380/b2490cce-2e3c-100f-86c4-656ac8a723ce.png)


## 方法2
Viewを2つ使って、1つはAlign Bottom to: Safe Area、もう1つはBottom Space to: Superview に。
この2つのViewのTop Edgeを同じにする。
![Screen Shot 2017-10-16 at 3.47.27.png](https://qiita-image-store.s3.amazonaws.com/0/1380/d2076919-4c18-2694-3f03-9697916ce529.png)

派生版として、この2つのViewを続けて配置するパターンもあるが、0.5ptの隙間が開くことがあったのであまりオススメしない。

![Screen Shot 2017-10-16 at 4.00.55.png](https://qiita-image-store.s3.amazonaws.com/0/1380/afcf88af-5416-3166-df26-05cfa3f48b9f.png)


## 方法3
Storyboardの「Use Safe Area Layout Guides」をONにする。
2つのViewを親子の階層にする。
親のViewのSafe Area Layout Guideにチェックをいれる。
![Screen Shot 2017-10-16 at 4.05.56.png](https://qiita-image-store.s3.amazonaws.com/0/1380/c74d994d-1a7d-09ae-e3dd-318afb6f80f2.png)

子ViewのBottomの制約を、Align Bottom to: Safe Area にする。
![Screen Shot 2017-10-16 at 3.51.57.png](https://qiita-image-store.s3.amazonaws.com/0/1380/c7a78d45-9ecc-f4a9-b3c2-60ac2cde53fc.png)



# Insetsが設定されるタイミング

コードで、Insetsの値を考慮したコンテンツサイズからゴニョゴニョする場合、そのタイミングが大事。
viewDidLoadのタイミングではInsetsは設定されていないからです。
基本的には ***DidChange のメソッドが用意されているので、そのタイミングをトリガーします。

具体的に、どのタイミングで設定されるのかをログをとってみました。
半透明なナビゲーションバー、タブバーとテーブルを配置し、iPhone6sのシミュレータで実行したものです。
各メソッドが呼ばれた順に、その時点の値を記述しています。

## UIViewController.safeAreaInsets

(iOS11で追加)
viewSafeAreaInsetsDidChange以降で確定

| Timing | Top | Left | Bottom | Right |
|---|---|---|---|---|
| loadView | 0.0 | 0.0 | 0.0 | 0.0 |
| viewDidLoad | 0.0 | 0.0 | 0.0 | 0.0 |
| viewWillAppear | 0.0 | 0.0 | 0.0 | 0.0 |
| viewSafeAreaInsetsDidChange | 64.0 | 0.0 | 49.0 | 0.0 |
| traitCollectionDidChange | 64.0 | 0.0 | 49.0 | 0.0 |
| viewDidAppear | 64.0 | 0.0 | 49.0 | 0.0 |

## UITableView.safeAreaInsets

(iOS11で追加)
子ViewであるUITableView の SafeAreaInsetsは、UIViewController.viewSafeAreaInsetsDidChangeではまだ確定していない。UITableViewのsafeAreaInsetsDidChange 以降で決まる

| Timing | | Top | Left | Bottom | Right |
|---|---|---|---|---|---|---|
| UIViewController| loadView | 0.0 | 0.0 | 0.0 | 0.0 |
| UIViewController| viewDidLoad | 0.0 | 0.0 | 0.0 | 0.0 |
| UIViewController| viewWillAppear | 0.0 | 0.0 | 0.0 | 0.0 |
| UIViewController| viewSafeAreaInsetsDidChange | 0.0 | 0.0 | 0.0 | 0.0 |
| UITableView | safeAreaInsetsDidChange |  64.0 | 0.0 | 49.0 | 0.0 |
| UIViewController| traitCollectionDidChange | 64.0 | 0.0 | 49.0 | 0.0 |
| UIViewController| viewDidAppear | 64.0 | 0.0 | 49.0 | 0.0 |

## UITableView.layoutMargins

### iOS11

iOS11の時は、SafeAreaInsetsの値も含めた合計値になる。
UITableView.layoutMarginsDidChangeは2回呼ばれた。1回目は端末サイズに合わせた値になったもの、2回目はSafeAreaの値が反映されたもの。


| Timing | | Top | Left | Bottom | Right |
|---|---|---|---|---|---|---|
| UIViewController| loadView | 8.0 | 8.0 | 8.0 | 8.0 |
| UIViewController| viewDidLoad | 8.0 | 8.0 | 8.0 | 8.0 |
| UIViewController| viewWillAppear | 8.0 | 8.0 | 8.0 | 8.0 |
| UITableView | layoutMarginsDidChange |  8.0 | 15.0 | 8.0 | 15.0 |
| UIViewController| viewSafeAreaInsetsDidChange | 8.0 | 15.0 | 8.0 | 15.0 |
| UITableView | layoutMarginsDidChange | 72.0 | 15.0 | 57.0 | 15.0 |
| UITableView | safeAreaInsetsDidChange | 72.0 | 15.0 | 57.0 | 15.0 |
| UIViewController| traitCollectionDidChange | 72.0 | 15.0 | 57.0 | 15.0 |
| UIViewController| viewDidAppear | 72.0 | 15.0 | 57.0 | 15.0 |

5.5インチの端末のTable.layoutMarginの左右は20ptになります。

### iOS10

| Timing | | Top | Left | Bottom | Right |
|---|---|---|---|---|---|---|
| UIViewController| loadView | 8.0 | 8.0 | 8.0 | 8.0 |
| UIViewController| viewDidLoad | 8.0 | 8.0 | 8.0 | 8.0 |
| UIViewController| viewWillAppear | 8.0 | 8.0 | 8.0 | 8.0 |
| UITableView | layoutMarginsDidChange |  8.0 | 15.0 | 8.0 | 15.0 |
| UIViewController| viewSafeAreaInsetsDidChange | 8.0 | 15.0 | 8.0 | 15.0 |
| UITableView | layoutMarginsDidChange | 8.0 | 15.0 | 8.0 | 15.0 |
| UIViewController| traitCollectionDidChange | 8.0 | 15.0 | 8.0 | 15.0 |
| UIViewController| viewDidAppear | 8.0 | 15.0 | 8.0 | 15.0 |



## UITableView.contentInset

UITableView.contentInsetは、iOS10とiOS11とで変わる。
iOS11では.zeroになり、代わりに、adjustedContentInsetに値が入る。

| Timing | | iOS10: Content Inset | iOS11:Content Inset |
|---|---|---|---|---|---|---|
| UIViewController| loadView | (0,0,0,0) | (0,0,0,0) |
| UIViewController| viewDidLoad | (0,0,0,0) | (0,0,0,0) |
| UIViewController| viewWillAppear | (0,0,0,0) | (0,0,0,0) |
| UIViewController| traitCollectionDidChange | (64, 0, 49, 0) | (0,0,0,0) |
| UIViewController| viewDidAppear |  (64, 0, 49, 0) | (0,0,0,0) |


## UITableView.adjustedContentInset

(iOS11で追加)
contentInsetAdjustmentBehaviorの設定により変わります。
デフォルトの automatic指定のときの結果です。

| Timing | | Top | Left | Bottom | Right |
|---|---|---|---|---|---|---|
| UIViewController| loadView | 0.0 | 0.0 | 0.0 | 0.0 |
| UIViewController| viewDidLoad | 0.0 | 0.0 | 0.0 | 0.0 |
| UIViewController| viewWillAppear | 0.0 | 0.0 | 0.0 | 0.0 |
| UITableView | layoutMarginsDidChange | 0.0 | 0.0 | 0.0 | 0.0 |
| UIViewController| viewSafeAreaInsetsDidChange | 0.0 | 0.0 | 0.0 | 0.0 |
| UITableView | layoutMarginsDidChange | 64.0 | 0.0 | 49.0 | 0.0 |
| UITableView | safeAreaInsetsDidChange | 64.0 | 0.0 | 49.0 | 0.0 |
| UITableView | adjustedContentInsetDidChange | 64.0 | 0.0 | 49.0 | 0.0 |
| UIViewController| traitCollectionDidChange | 64.0 | 0.0 | 49.0 | 0.0 |
| UIViewController| viewDidAppear | 64.0 | 0.0 | 49.0 | 0.0 |