Edited at

iOS11 + Xcode9.0でedgesForExtendedLayoutの値を空にしていると、UITableViewのドリルダウンでアニメーションが崩れる

More than 1 year has passed since last update.


背景

iOS7からUIViewControllerへ追加されたプロパティに、edgesForExtendedLayoutがあります。

このプロパティはNavigation Barの下にViewへ回り込ませるためのもので、デフォルトでは回り込むように値が設定されています。

スクリーンショット 2017-09-21 20.20.43.png

ここへ空を代入するか、Storyboardで「Under Top Bars」のチェック外すと、回り込みがなくなり、ViewはNavigation Barの下からスタートします。

edgesForExtendedLayout = []

スクリーンショット 2017-09-21 20.50.06.png

ちょっとわかりにくいですが、Navigation Barの下にはTableViewが回り込んでいません。

スクリーンショット 2017-09-21 20.21.23.png


発生した問題

この状態のアプリをXcode9.0でビルドすると問題が発生します。iOS11端末へ入れたときにTableViewだと画面遷移のアニメーションが不自然になります。

0921_test_trim.gif

微妙ですが、ナビゲーションを上る時に20ptほどの隙間が存在していて、上にスクロールしながら遷移します。edgesForExtendedLayoutをいじっていない時は以下のような挙動になります。こちらはきれいに遷移しています。

0921_test_2.gif


原因と解決策

調べてみると、こちらにバグレポートとして似たような現象が報告されていました。

iOS11からUIScrollViewへ導入されたadjustedContentInsetが悪さをしているようです。

このプロパティは、UINavigationControllerへ配置されたUIScrollViewに対して自動でInset値を付けてくれるものです。

UIScrollViewへ自前でcontentInsetsを設定していると、このプロパティの影響でレイアウト崩れを起こすという報告がいくつかされています。

対策としては、contentInsetAdjustmentBehaviorの値にneverを設定すればいいようです。

if #available(iOS 11.0, *) {

tableView.contentInsetAdjustmentBehavior = .never
}

この設定をしてみた所、今回のケースでも正常な状態となり、自然なアニメーションへ戻りました。

0921_test_3_trim.gif

他のケースと異なり、UITableViewで特にcontentInsetsを設定していなくてもadjustedContentInsetの影響を受けることがあったので、こちらへまとめておきます。

バグレポートとして報告されていることから、将来のバージョンでは修正されているかもしれません。


追記 (2017/10/11) : contentInsetAdjustmentBehaviorをneverにした時のiPhoneXでのSafeArea問題

上記設定をした時に気をつける必要がある問題として、UIScrollViewが勝手にやってくれるSafe Area設定が無効になってしまうという点があります。例えば、下部にUITabBarなどを置かずにUITableViewが一番下に接触している場合、iPhoneXで以下の状態になります。 Home Indicatorと一番下のセルが被ってしまい、ガイドライン的によろしくない状態となってしまいます。

スクリーンショット 2017-10-11 22.19.13.png

その問題を解消するために、frameやinsetsの値を変更する時のタイミングなどで、safeAreaInsetsのbottomを入れてやる必要があるでしょう。(safeAreaInsetsの全てをそのまま設定するとLandscapeにした時にTableViewでは左右のレイアウトが崩れてしまいます。)

override func viewWillLayoutSubviews() {

super.viewWillLayoutSubviews()
if #available(iOS 11.0, *) {
tableView.contentInset.bottom = view.safeAreaInsets.bottom
}
}

そうすると以下のようにHome Indicatorの領域の上までスクロールされるようになります。

スクリーンショット 2017-10-11 22.22.24.png

スクリーンショット 2017-10-11 22.29.02.png


参考資料