Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

safeAreaInsets in UIView is 0 on an iPhone X

I am updating my app to adapt it for iPhone X. All views work fine by now except one. I have a view controller that presents a custom UIView that covers the whole screen. Before I was using UIScreen.main.bounds to find out the size of the view before all layout was done (I need it for putting the correct itemSize for a collectionView). I thought that now I could do something like UIScreen.main.bounds.size.height - safeAreaInsets.bottom to get the right usable size. The problem is, safeAreaInsets returns (0,0,0,0) trying on an iPhone X (Simulator). Any ideas? In other views, I get the right numbers for safeAreaInsets.

Thank you!

like image 502
Joan Cardona Avatar asked Oct 31 '17 10:10

Joan Cardona


People also ask

What is safeAreaInsets?

Fresh out of WWDC21, safeAreaInset() is a brand new SwiftUI view modifier, which lets us define views that become part of the observed safe area.


4 Answers

I recently had a similar problem where the safe area insets are returning (0, 0, 0, 0) as soon as viewDidLoad is triggered. It seems that they are set fractionally later than the rest of the view loading.

I got round it by overriding viewSafeAreaInsetsDidChange and doing my layout in that instead:

override func viewSafeAreaInsetsDidChange() {
 // ... your layout code here
} 
like image 124
Richard West-Soley Avatar answered Oct 21 '22 11:10

Richard West-Soley


I already figure out the solution: I was doing all the implementation in the init of the view. safeAreaInsets has the correct size in layoutSubviews()

like image 46
Joan Cardona Avatar answered Oct 21 '22 12:10

Joan Cardona


I've run into this issue too trying to move up views to make way for the keyboard on the iPhone X. The safeAreaInsets of the main view are always 0, even though I know the subviews have been laid out at this point as the screen has been drawn. A work around I found, as and mentioned above, is to get the keyWindow and check its safe area insets instead.

Obj-C:

CGFloat bottomInset = [UIApplication sharedApplication].keyWindow.safeAreaInsets.bottom;

Swift:

let bottomInset = UIApplication.shared.keyWindow?.safeAreaInsets.bottom

You can then use this value to adjust constraints or view frames as required.

like image 42
Rory Prior Avatar answered Oct 21 '22 13:10

Rory Prior


I have a view which is a subview inside another view. I found that I can't get safeAreaInsets correctly, it always return 0, in that view on iPhoneX even if I put it in layoutSubviews. The final solution is I use following UIScreen extension to detect safeAreaInsets which can work like a charm.

extension UIScreen {

    func widthOfSafeArea() -> CGFloat {

        guard let rootView = UIApplication.shared.keyWindow else { return 0 }

        if #available(iOS 11.0, *) {

            let leftInset = rootView.safeAreaInsets.left

            let rightInset = rootView.safeAreaInsets.right

            return rootView.bounds.width - leftInset - rightInset

        } else {

            return rootView.bounds.width

        }

    }

    func heightOfSafeArea() -> CGFloat {

        guard let rootView = UIApplication.shared.keyWindow else { return 0 }

        if #available(iOS 11.0, *) {

            let topInset = rootView.safeAreaInsets.top

            let bottomInset = rootView.safeAreaInsets.bottom

            return rootView.bounds.height - topInset - bottomInset

        } else {

            return rootView.bounds.height

        }

    }

}
like image 21
Shih Ken Avatar answered Oct 21 '22 12:10

Shih Ken