Saturday, August 27, 2016

iOS auto layout and status bar

iOS statusbar is a little different from other ui element, although it shows content belongs to the device, instead of the current UIViewController, it is part of the UIViewController's view area, and it is managed by UIViewController.

Each UIViewController can decide to show or hide the statusbar by implementing the below method which will be called by ios, the method uses the return value to tell ios whether status should be shown or not for the current UIViewController.

-(BOOL) prefersStatusBarHidden{
    return bshowStatusBar;
}

The problem is the ios only calls this method once when initially displaying the view controller. After that if the view controller wants to change the statusbar hide/show status, then it needs to call the below method to tell ios, to call the above method again to get the updated return value from view Controller.


    [this setNeedsStatusBarAppearanceUpdate];  //this is the current view controller

Most time the content in the UIViewController should below the statusbar, quite often, developers just set auto layout's constraint with the top of the view element to the top of the root view element with 25 distance. This usually works, but if the statusbar state changed in the middle, then the hardcoded 25 vertical distance will break the function.

The proper way to do so is setting the auto layout's constraint with the top of the view element to the bottom of the root view's topLayoutGuide, as the topLayoutGuide will be automatically updated when status bar state changes, so the auto layout will automatically set the view element in proper position no matter statusbar is hidden or shown.

The below is a sample code to set the constraint programmatically

  webview = [[UIWebView alloc] init];
  [webview setTranslatesAutoresizingMaskIntoConstraints:NO];
  [self.view addSubview:webview];
    

 [self.view addConstraint:[NSLayoutConstraint constraintWithItem:webview attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0]];

 [self.view addConstraint:[NSLayoutConstraint constraintWithItem:webview attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0]];

 [self.view addConstraint:[NSLayoutConstraint constraintWithItem:webview attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.topLayoutGuide attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0]];

 [self.view addConstraint:[NSLayoutConstraint constraintWithItem:webview attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.bottomLayoutGuide attribute:NSLayoutAttributeTop multiplier:1.0 constant:0]];
    
[webview loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.google.com"]]];


Note in order to let application to decide the status bar state instead of each UIViewController, specify the below keyvalue pair in the xcode project plist file

<key>UIStatusBarHidden</key>
<true/>
<key>UIViewControllerBasedStatusBarAppearance</key>

<false/>