Insets
半透明のナビゲーションバーやタブバーを配置して、下のテーブルの内容が潜り込んで見えるようにする場合、Insetsでその量を指定します。
iOS10の時は、「Adjust Scroll View Insets」にチェックを入れると、配置しているTableViewなどScrollView系のコンポーネントのContentInsetsが自動的に設定される仕組みになっていました。
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のサイズ
半透明なナビゲーションバー、タブバーを配置した時の各種サイズです。
ステータスバーが20→44ptに代わり、BottomにHomeIndicatorのエリアとして34pt追加されます。
端末を横にした時には左右のInsetsが44pt出てきます。
Table.layoutMarginの値は、「Preserve Superview Margins」がOFFの時の値です。
iPhoneXのBottom部分に色を塗る3つの方法
こんな感じで色を塗りたい場合。
方法1
Align Bottom to: Safe Areaにして、UIViewController.view.backgroundColorを同じ色で塗る。
コレでいけるのであれば一番ラク。
方法2
Viewを2つ使って、1つはAlign Bottom to: Safe Area、もう1つはBottom Space to: Superview に。
この2つのViewのTop Edgeを同じにする。
派生版として、この2つのViewを続けて配置するパターンもあるが、0.5ptの隙間が開くことがあったのであまりオススメしない。
方法3
Storyboardの「Use Safe Area Layout Guides」をONにする。
2つのViewを親子の階層にする。
親のViewのSafe Area Layout Guideにチェックをいれる。
子ViewのBottomの制約を、Align Bottom to: Safe Area にする。
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 |