Status bar colours

Did you know that UIApplication.setStatusBar[Style|Hidden] has been deprecated in iOS9? We all know that Apple are ruthless in deprecating old API's, so it's time that we got on board with the new(ish) viewcontroller-based status bar style API's. Here's everything you need to know:

Info.plist

It's now deprecated to have UIViewControllerBasedStatusBarAppearance=NO in your Info.plist file. It was common for people to use this as the 'nuclear option' - that is, you set your status bar style in the plist and it overrides the entire app. I can empathise with developers taking this shortcut but we really shouldn't any more. I recommend removing this key from the plist entirely (as opposed to setting it to YES).

You'll still want to use the following keys to set the status bar style for your launch screen, since the launch screen is visible before any code runs:

  • UIStatusBarHidden aka "Status bar is initially hidden"
  • UIStatusBarStyle aka "Status bar style"

New API

So we should all now be using the following in (most of) our view controllers. I'll get to why I said 'most of' later...

  • preferredStatusBarStyle (white or black status bar content)
  • preferredStatusBarUpdateAnimation ("Specifies the animation style to use for hiding and showing the status bar for the view controller")
  • prefersStatusBarHidden

In Swift, it looks like doing the following in your UIViewController subclass:

override func preferredStatusBarStyle() -> UIStatusBarStyle {
    return .LightContent
}
override func prefersStatusBarHidden() -> Bool {
    return true
}
override func preferredStatusBarUpdateAnimation() -> UIStatusBarAnimation {
    return .Slide
}

FYI: they have to be overridden functions instead of setting them as variables because they are methods not properties in the UIViewController source .

Note: You don't need to override all these methods every time, only where you depart from the default style, which is black+visible+fade, respectively.

And if your view controller ever needs to change its status bar for some reason, simply call setNeedsStatusBarAppearanceUpdate and change the code in your preferredStatusBarStyle to reflect whatever you want it to look like.

Navigation Controllers

It all gets more 'interesting' when there's a UINavigationController involved. And by 'interesting' I mean 'a little complicated'. But read on and you'll be fine, and hopefully you'll get back to feeling like you're in control of your status bars.

And this is why I said 'most of' earlier - oftentimes, view controllers inside a navigation controller don't need an explicit style since the navigation controller dictates the status bar style.

So here's the rule of thumb:

If the navigation controller's navigation bar is visible, then it is responsible for the status bar

In other words:

  • If UINavigationController.navigationBarHidden = false, the UINavigationController's preferredStatusBarX methods are called, after all it is displaying the content under the status bar.
  • If UINavigationController.navigationBarHidden = true, the child UIViewController's preferredStatusBarX methods are called, since the child is displaying the content under the status bar.

Here's a twist: If you don't like the above behaviour, and would like your navigation controller to pass on responsibility for the status bar to the child view controllers for some reason, you can't simply subclass UINavigationController, override preferredStatusBarX, and call through to topViewController. This is because UIKit has a private mathod called UIApplication._updateCurrentStatusBarViewControllerAppearance, which in turn calls your nav controller's _currentStatusBarHiddenViewController to get the child, then calls the child directly, leaving your nav controller out of the loop with no way to intervene. So don't bother trying unless you want to burn several hours like I did.

Now, UINavigationController isn't really designed to be subclassed. So you're not supposed to subclass it and override preferredStatusBarStyle to get white status bar content. Instead, the colour of the status bar comes from navigationBar.barStyle: .Default = black status bar content; .Black = white status bar content.

Important: So if you're setting barTintColor to your brand's colour (which you likely are), you also need to set barStyle to .Black to get white status bar content. I'd set barStyle to black before setting barTintColor, in case barStyle overrides the barTintColor for whatever reason.

Modals

Modals act as you'd expect: A modally displayed UINav with a navigation bar dictates the colour via the barStyle, otherwise UIViewController's preferX get called. However, there's one more twist:

Modally displayed UIViewController's only get a say in the status bar if modalPresentationStyle = .FullScreen. Other presentation styles don't get a say in the status bar by default. I guess UIKit assumes that partial-screen modals (eg a UIAlertController) don't cover the status bar - a reasonable assumption!

However, if you've got a custom presentation style modal view controller and you really want it to control the status bar for some reason, you can override modalPresentationCapturesStatusBarAppearance to return true.

That's it! Everything you wanted to know about how to get that status bar to do what you wanted.

Thanks for reading! And if you want to get in touch, I'd love to hear from you: chris.hulbert at gmail.

Chris Hulbert

(Comp Sci, Hons - UTS)

iOS Developer in Sydney.

I have worked at places such as Google, Cochlear, News Corp, Fox Sports, NineMSN, FetchTV, Woolworths, and Westpac, among others. If you're looking for a good iOS developer, drop me a line!

Get in touch:
[email protected]
github.com/chrishulbert
linkedin
my resume



 Subscribe via RSS