ScrollViewに2つの子viewControllerが含まれています。 VC2が正しくレイアウトされていないことがわかります。
ビューがまだ画面上に表示されていない場合は見つかりました。 safeAreaInsets
は常に0です。
スクロールが終了したときにvc2.view.setNeedsLayout()
を呼び出して、この問題を修正できます。しかし、レイアウトはスクロールが終了するまで正しくありません。
ドキュメント は言う
ビューが現在ビュー階層にインストールされていない場合、またはまだ画面に表示されていない場合、このプロパティのエッジインセットは0です。
どうすればこの状況を修正できますか?.
現在のビューのsafeAreaInsetsを参照する代わりに、UIApplicationに設定します。
(UIApplication.shared.delegate?.window??.safeAreaInsets.bottom)
子ビューコントローラーで、ビューコントローラーadditionalSafeAreaInsets
をウィンドウのセーフエリアインセットと等しく設定すると、セーフエリアを考慮して正しくレイアウトされます。
viewDidLoad()
とviewWillTransition(to size: CGSize, with coordinator: UIVIewControllerTransitionCoordinator
の内部でこれを行う必要があることがわかりました
viewWillTransition
の内部では、コーディネーターのアニメーションブロックにadditionalSafeAreaInsets
を設定します。
coordinator.animate(alongsideTransition: { _ in
if #available(iOS 11.0, *) {
self.additionalSafeAreaInsets = UIApplication.shared.delegate?.window??.safeAreaInsets
}
}, completion: nil)
私はカスタムページングビューコントローラーを作成していて、この問題と@PowHUに遭遇しました。
私にとってうまくいくように思えた唯一の解決策は、ストーリーボードのビューコントローラーのビュークラスを、作成したカスタムクラスAlwaysSafeAreaInsetsView
に設定することでした。
import UIKit
class AlwaysSafeAreaInsetsView: UIView {
@available(iOS 11.0, *)
override var safeAreaInsets: UIEdgeInsets {
if let window = UIApplication.shared.keyWindow {
return window.safeAreaInsets
}
return super.safeAreaInsets
}
}
私が適切に表示する場合、コンテナービューはスーパービューの上部と下部に固定されています。これを安全領域に固定すると、子のビューコントローラが適切に配置されます。