仕事でiPhoneX対応をしたのですが、あまりにどこから手をつけていいかわからず、泣きそうになりました。泣いてないけど。
小枝チョコを1日で40本食べるくらいには思いつめたので、そんな人が他にもいた時のために、メモっておきます。
概要
SafeAreaとは
Appleがガイドラインで明記している、iPhoneXで表示する際に必要な上下左右のスペースのこと。
https://developer.apple.com/ios/human-interface-guidelines/overview/iphone-x/
https://developer.apple.com/documentation/uikit/uiview/positioning_content_relative_to_the_safe_area
厳密には、単語は以下の定義?(個人的な解釈。正しいか不明)
- SafeArea
- 上部のステータスバーと下部のホームバーを除いたエリアのこと
- Margin
- 左右に必要なスペース
- 画面を回転させるとサイズも変わる
SafeArea内に納めるためには
AutoLayoutでSafeArea内でどうやって表示するか設定すれば良さそう
部品のサイズをコードで計算して配置している場合は、
計算するときにSafeAreaの値を取得して、なんやかんやする。
対応
StoryBoard/xibSafeArea

SafeArea内に良きように収めてもらうために、AutoLayoutを設定する。
対応前。
濃い緑の部分がSafe Areaで、薄い緑の部分が、Safe Areaからはみ出している部分。
赤枠のUse Auto Layout
と、Use Safe Area Layout Guide
にチェックを入れる。
Safe Areaに収まるように要素を配置し直す。
(これ全てのページやるの?!!!めんどう…)
Constraints = 制約をつける。
赤線で I 文字のようになっている部分をクリックして、設定画面を出す。
基準となる箇所を、Safe Areaにする。
Add * Constraints
をクリックする。
これをしないと制約が設定されないので注意。
オレンジ枠の場所で、制約がちゃんと設定されていることを確認。
ナビゲージョンバーが上部にある場合
上記の手順で対応したところ、iOS11では期待通りに表示されるが、
iOS10だと、思った位置に表示されない(配置した要素がナビゲーションバーに被ってしまう)事象が発生。
↓
https://qiita.com/yaslam/items/4901a490ecf2812534a3
これを参考に解決。
ナビゲーションバーやツールバーがある場合は、
Constraintsの設定のところで、
- SuperViewを起点にして制約を設定して、
Constraints to Margins
にチェックを入れて、- Add Constraints
すると、期待通りに表示される。
Margin
Constraintsの設定のところで、Constraints to Margins
にチェックを入れて、Add Constraintsする。んだと思う。
試してないので本当にそれでできるのかは不明。
コード
制約をつけたい部分のAnchor
に対し、 constraintEqualToAnchor
で基準となるAnchor
を指定し、active
にする。
SafeArea
self.webViewの上辺をSafe Areaに合わせた例。
[self.webView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor].active = YES;
self.view.safeAreaLayoutGuide
に合わせるように指定する。
Margin
self.webViewの左辺(leading)にMarginを持たせた例。
[self.webView.leadingAnchor constraintEqualToAnchor:self.view.layoutMarginsGuide.leadingAnchor].active = YES;
https://qiita.com/yimajo/items/10f16629200f1beb7852self.view.layoutMarginsGuide
で、必要なマージンが取得できるようなので、それに合わせるように指定。
実装
最終的にはこんな感じ。
iOS10以下も対応必要があるので、分岐させています。
Before[self.view addConstraints:@[
[NSLayoutConstraint constraintWithItem:self.webView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.topLayoutGuide
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0],
[NSLayoutConstraint constraintWithItem:self.webView
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:0],
[NSLayoutConstraint constraintWithItem:self.webView
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:0],
[NSLayoutConstraint constraintWithItem:self.webView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.Button
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:-43]
]];
}
Afterif (@available(iOS 11, *)) {
[self.webView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor].active = YES;
[self.webView.leadingAnchor constraintEqualToAnchor:self.view.layoutMarginsGuide.leadingAnchor].active = YES;
[self.webView.trailingAnchor constraintEqualToAnchor:self.view.layoutMarginsGuide.trailingAnchor].active = YES;
[self.webView.bottomAnchor constraintEqualToAnchor:self.Button.topAnchor constant:-43].active = YES;
} else {
[self.view addConstraints:@[
[NSLayoutConstraint constraintWithItem:self.webView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.topLayoutGuide
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0],
[NSLayoutConstraint constraintWithItem:self.webView
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:0],
[NSLayoutConstraint constraintWithItem:self.webView
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:0],
[NSLayoutConstraint constraintWithItem:self.webView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.Button
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:-43]
]];
}
[self.view addConstraints:@[
[NSLayoutConstraint constraintWithItem:self.webView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.topLayoutGuide
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0],
[NSLayoutConstraint constraintWithItem:self.webView
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:0],
[NSLayoutConstraint constraintWithItem:self.webView
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:0],
[NSLayoutConstraint constraintWithItem:self.webView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.Button
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:-43]
]];
}
if (@available(iOS 11, *)) {
[self.webView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor].active = YES;
[self.webView.leadingAnchor constraintEqualToAnchor:self.view.layoutMarginsGuide.leadingAnchor].active = YES;
[self.webView.trailingAnchor constraintEqualToAnchor:self.view.layoutMarginsGuide.trailingAnchor].active = YES;
[self.webView.bottomAnchor constraintEqualToAnchor:self.Button.topAnchor constant:-43].active = YES;
} else {
[self.view addConstraints:@[
[NSLayoutConstraint constraintWithItem:self.webView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.topLayoutGuide
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0],
[NSLayoutConstraint constraintWithItem:self.webView
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:0],
[NSLayoutConstraint constraintWithItem:self.webView
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:0],
[NSLayoutConstraint constraintWithItem:self.webView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.Button
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:-43]
]];
}
こんな感じに変更。
高さ
サイズや位置を計算している箇所には、下記で対応。
現在表示されているバーの値を取得するには以下
// ステータスバー
[UIApplication sharedApplication].statusBarFrame.size.height;
// ナビゲーションバー
self.navigationController.navigationBar.frame.size.height;
Tips
Tableのアニメーションがなんか変なとき
iOS11 + Xcode9.0でedgesForExtendedLayoutの値を空にしていると、UITableViewのドリルダウンでアニメーションが崩れる - Qiita背景iOS7からUIViewControllerへ追加されたプロパティに、edgesForExtendedLayoutがあります。edgesForExtendedLayout - UIViewC…

コメント