10

I've been trying to change the color of the status bar in my Swift app, and I've identified four ways to do this in XCode. Yet, I have only been able to successfully use method 3:

1. Simulated Metrics (For Storyboard display only)

2. Change in General->Deployment Info->Status Bar Style

Make sure the following Info.list setting is set to "NO":

View controller-based status bar appearance : NO

Select either "Light" or "Default" in the dropdown box here:

General->Deployment Info->Status Bar Style

3. Set it Manually

Make sure the following Info.plist setting is set to "NO":

View controller-based status bar appearance : NO

Insert the following code (usually in didFinishLaunchingWithOptions):

UIApplication.sharedApplication().statusBarStyle = .LightContent

4. Override "preferredStatusBarStyle()"

Make sure the following Info.plist property exists and is set to "YES":

View controller-based status bar appearance : YES

Then add the following code to the UIViewController (or derived class) which is set for your ViewController in Storyboard:

override func preferredStatusBarStyle() -> UIStatusBarStyle {
    return UIStatusBarStyle.LightContent
}

My current understanding

Simulated Metrics is just for display and provides no actual change during runtime. I believe setting manually and changing the setting in the general tab probably do the same thing under the hood, but I'm not sure. I imagine there is also a way to set this property directly for individual view controllers.

Question

For some reason, the only method which has actually worked for me is method 3, setting manually. None of the other methods provide any change. Personally, I would prefer to override in a derived class so I have a central place for my shared UIViewController styles.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Veita
  • 509
  • 1
  • 5
  • 16
  • **Simulated Metrics** are just that: ***simulated***. Changing simulated metrics doesn't change *anything* at run time. – nhgrif Apr 17 '16 at 15:38
  • Yes, this was my understanding as well. I am mostly looking for an explanation as to why the other 2 methods do not work. Simulated Metrics will do nothing but change the XCode Storyboard preview. – Veita Apr 17 '16 at 15:40
  • 1
    Actually, methods 2 and 3 are working properly, but what I originally posted is mistaken. For these methods to work (at least for me), the Info.plist property must exist and it must be set to "NO". Otherwise, these methods do not have any effect. – Veita Apr 17 '16 at 15:51

1 Answers1

12

Option 1

This does nothing because it's just a simulated metric. You can set it in interface builder, but simulated metrics are just simulated and not applied at run time.

Option 2

This option prevents individual view controllers from setting the status bar appearance (due to the Info.plist setting), and it relies on a default color set in deployment settings, but that value can be changed at run time (see option 3).

Option 3

Like option 2, this option prevents individual view controllers from setting the status bar appearance (due to the Info.plist setting), but unlike option 2, we're dynamically setting the color at run time. We can do this just in the app delegate at launch... or we can change it at various other times. Maybe we have a night mode like the Google Maps app, or maybe we're letting the user configure their own theme colors somewhere.

Option 4

If you are embedding in a UINavigationController, then you will need to subclass UINavigationController and override "preferredStatusBarStyle()" here.

You may be missing a step, outlined here. In viewDidLoad, try specifying that you want the opportunity to set the status bar.

override func viewDidLoad() {
    super.viewDidLoad()

    setNeedsStatusBarAppearanceUpdate()
}

As to why there are different approaches for seemingly the same thing, we must first realize that these aren't actually the same thing.

Again, let's break it down.

  • Option 1 isn't a run time change, so it's really not interesting to us.
  • Option 2 & 3 are almost the same thing.
  • Option 4 is different from option 2 & 3.

Why do we have your option 2/3 and your option 4?

Because in some applications, you might want the same status bar color for every view controller in your app, but that status bar color might be different based on some setting.

Consider, for example, Google Maps app. At night, the app turns black and the status bar needs to show up white, but at day, the app is white and the status bar needs to be black. It's the same for every view controller, so the code to set the color needs to just be implemented in one place (without requiring every view control inherit from the same base parent). For this, we likely want your option 2/3.

But consider an app that has different colored view controllers where the some of them look better with a white status bar and others look better with a black. For this approach, we want your option 4 and let each view controller individually specify what color the status bar should be.

In short, your option 2/3 is a global status bar setting that applies no matter where you are in the app, while option 4 is a local, per-VC setting.

Community
  • 1
  • 1
nhgrif
  • 61,578
  • 25
  • 134
  • 173
  • Great, thank you for the explanation of option 4 and confirming the function of each option. I can also see that option 4 is useful if you prefer to subclass UIViewController, as you can then create a batch of views which inherit the same style. I will add that for me, option 2 alone will change the global style of the status bar, but it will be overridden by method 3. – Veita Apr 17 '16 at 16:06
  • Option 2 is just the first half of option 3. Option 3 fully encompasses everything you do in option 2. – nhgrif Apr 17 '16 at 16:07
  • Maybe I don't understand, but when I use option 2 as described in the original post (making sure the Info.plist entry exists and is set to NO) then the global effect appears identical to option 3. But, option 3 will override the setting of option 2. – Veita Apr 17 '16 at 16:10
  • Your complete set of steps for option 2 appear to be identical to the first half of option 3. What are you doing in option 2 that you're not doing in option 3? – nhgrif Apr 17 '16 at 16:11
  • I select either "Light" or "Default" for "General->Deployment Info->Status Bar Style". – Veita Apr 17 '16 at 16:12
  • Updated the post to make the difference explicit. – Veita Apr 17 '16 at 16:14
  • Oh, I see. Yeah, this is just a global setting. Setting it there is just giving it a default. It will always be overridden by the last step you outline in Option 3. But the point is, that code from option 3 can be called from anywhere at any time, dynamically, like the Google Maps example I outlined. If you don't need to ever dynamically set it, setting it in deployment info is fine and you don't need the code. – nhgrif Apr 17 '16 at 16:14
  • Hmm, for some reason even after following the steps I gave in option 4 and additionally calling "setNeedsStatusBarAppearanceUpdate()" from viewDidLoad(), I am still not seeing the status bar change properly. – Veita Apr 17 '16 at 16:26
  • Is the function being called? (Are you putting the function in an extension, btw?) – nhgrif Apr 17 '16 at 16:28
  • Ok, I got it working. In my case, I had a view embedded in a UINavigationController. To make option 4 work in my case, I needed to subclass UINavigationController and override "preferredStatusBarStyle" here. I have not found adding "setNeedsStatusBarAppearanceUpdate()" to be necessary though, as it works properly without this line. – Veita Apr 17 '16 at 16:37