PowHu
PowHu

Reputation: 2189

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

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

Upvotes: 15

Views: 7985

Answers (4)

SamB
SamB

Reputation: 3323

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
    }

}

Upvotes: 2

Kylelol
Kylelol

Reputation: 161

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)

Upvotes: 3

ajayb
ajayb

Reputation: 633

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

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

Upvotes: 12

jonaszmclaren
jonaszmclaren

Reputation: 2489

If I see properly your container view is pinned to the top and bottom of it's superview. Pin it to the Safe Area, and your child view controllers will be laid out properly.

Upvotes: 0

Related Questions