Safe area not work properly on iPhone X when subviews are not in the view area

Viewed 6967

I have a scrollView contains 2 child viewController. You can see VC2 not layout properly.

I found if view is not yet visible onscreen. safeAreaInsets is always 0.

I can call vc2.view.setNeedsLayout() to fix this problem when scroll ended. But the layout is not correct until scroll ended.

The document says

If the view is not currently installed in a view hierarchy, or is not yet visible onscreen, the edge insets in this property are 0.

So how can I fix this situation.

enter image description here

Autolayout enter image description here enter image description here

4 Answers

instead of referencing the current view's safeAreaInsets, set it to the UIApplication:

(UIApplication.shared.delegate?.window??.safeAreaInsets.bottom)

In your child view controllers if you set the view controllers additionalSafeAreaInsets equal to the window's safe area insets they will layout correctly respecting the safe areas.

I found I had to do this inside of viewDidLoad() and viewWillTransition(to size: CGSize, with coordinator: UIVIewControllerTransitionCoordinator

Inside of viewWillTransition you will want to set the additionalSafeAreaInsets in the animation block of the coordinator:

coordinator.animate(alongsideTransition: { _ in
    if #available(iOS 11.0, *) {
        self.additionalSafeAreaInsets = UIApplication.shared.delegate?.window??.safeAreaInsets
    }
}, completion: nil)

I was building a custom paging view controller and ran into this issue as well @PowHU.

The only solution that seemed to work for me was to set the view controller's view class in the storyboard to a custom class I created called 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
    }

}
Related