iOS
UIKit
ios11

iOS11のInsetsとLayout

More than 1 year has passed since last update.

Insets

views.png

半透明のナビゲーションバーやタブバーを配置して、下のテーブルの内容が潜り込んで見えるようにする場合、Insetsでその量を指定します。
iOS10の時は、「Adjust Scroll View Insets」にチェックを入れると、配置しているTableViewなどScrollView系のコンポーネントのContentInsetsが自動的に設定される仕組みになっていました。
adjustInsets.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

iPhoneXLandscape.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

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

方法1

Align Bottom to: Safe Areaにして、UIViewController.view.backgroundColorを同じ色で塗る。
コレでいけるのであれば一番ラク。
Screen Shot 2017-10-16 at 3.40.37.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

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

Screen Shot 2017-10-16 at 4.00.55.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

子ViewのBottomの制約を、Align Bottom to: Safe Area にする。
Screen Shot 2017-10-16 at 3.51.57.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