Safe area insets change when hiding status bar iOS 11

Constraints that are set to the safe area are affected by the status bar as well as the views actual location on the screen and its transform. If you always want to just apply the top (or bottom) safe area height to your view constraint, you can do this by use of a custom constraint instead.

The following constraint will automatically set its constant value to the height of the device's top safe area height, not affected by the status bar or other parameters. To use it, change the class of any constraint into this, and their constant will always be the safe area height. Note that it will not change its value when the device is rotated.

Objective-C

@interface TopSafeAreaContraint : NSLayoutConstraint

@end

@implementation TopSafeAreaContraint

- (void)awakeFromNib {
    [super awakeFromNib];

    if (@available(iOS 11.0, *)) {
        UIEdgeInsets insets = [UIApplication sharedApplication].keyWindow.safeAreaInsets;
        self.constant = MAX(insets.top, 20.0);
    } else {
        // Pre-iOS 11.0
        self.constant = 20.0;
    }
}

@end

Swift

class TopSafeAreaConstraint: NSLayoutConstraint {
    override func awakeFromNib() {
        super.awakeFromNib()
        if #available(iOS 11.0, *) {
            let insets = UIApplication.shared.keyWindow?.safeAreaInsets ?? .zero
            self.constant = max(insets.top, 20)
        } else {
            // Pre-iOS 11.0
            self.constant = 20.0
        }
    }
}

I've been experiencing a similar issue so I came up with a slightly different approach. This is not a direct answer to the problem. It is a workaround which worked in my case.

I had two different view controllers, both of which must have a navigation bar (but a navigation controller is not required). The 1st view controller is presenting the 2nd one in a modal fashion. The problem is that the 2nd view controller is landscape only, which means that on iPhones with edge-to-edge displays any overrides of prefersStatusBarHidden are ignored and the system always returns true (see here).

What I did was simulate the status bar height through a custom view, and then adjust the height constraint constant in viewDidLoad(_:).

enter image description here

enter image description here

I got no ugly navbar or view controller jumps after that.

Tags:

Ios