29

Adding

application.statusBarStyle = .lightContent

to my AppDelegate's didFinishLaunchingWithOptions method nor adding

override var preferredStatusBarStyle: UIStatusBarStyle {
    return UIStatusBarStyle.lightContent
}

to the VC no longer works on iOS12/Xcode10

Any ideas?

Nostradamus
  • 1,497
  • 3
  • 20
  • 34
  • 1
    Works fine here, when it should work (i.e. when your view controller is the top-level view controller). You need to describe your situation more fully if you want actual help. – matt Sep 22 '18 at 02:38
  • Thanks for the response - developing on an iPhone X I'm trying to make the status bar area brighter - for example, the text on the time, the bars on the cellular reception status show up as black, and I have a dark themed UI. I'm using the above-mentioned VC code in the top-level view controller. I'm seeing comments from others saying the same thing about this not working in iOS 12 but it seems to work from you - I'll re-examine. – Nostradamus Sep 22 '18 at 02:50
  • Notice that your question never mentioned iPhone X... Hmmm, let me test that particular combination. You’re not in a navigation controller? – matt Sep 22 '18 at 03:53
  • Yes, I'm in a uinavigationcontroller, the vc is the first one in the stack. – Nostradamus Sep 22 '18 at 04:49
  • Your question never mentioned the navigation controller either. – matt Sep 22 '18 at 14:25

7 Answers7

121

This has nothing to do with iOS 12. You just have the rules wrong.

In a navigation controller situation, the color of the status bar is not determined by the view controller’s preferredStatusBarStyle.

It is determined, amazingly, by the navigation bar’s barStyle. To get light status bar text, say (in your view controller):

self.navigationController?.navigationBar.barStyle = .black

Hard to believe, but true. I got this info directly from Apple, years ago.

You can also perform this setting in the storyboard.

Example! Navigation bar's bar style is .default:

enter image description here

Navigation bar's bar style is .black:

enter image description here

NOTE for iOS 13 This still works in iOS 13 as long as you don't use large titles or UIBarAppearance. But basically you are supposed to stop doing this and let the status bar color be automatic with respect to the user's choice of light or dark mode.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • 2
    Matt, thanks for the responses and the illustrations, very helpful! – Nostradamus Sep 22 '18 at 21:43
  • 1
    Right but what I'm saying is that it's much better to do this (the right way) than to set UIViewControllerBasedStatusBarAppearance to false. – matt Sep 22 '18 at 21:48
  • Really nice insight, I always did the accepted answer approach, which was a real pain. I knew the UINavigationController was guilty, but I just didn't stop to figure out why exactly. Thanks for the info @matt, that's sad how Apple simple doesn't mention it anywhere - or at least not clearly in its docs. The status bar is so simple, yet so obscure. – Guilherme Matuella Oct 22 '18 at 23:56
  • Thanks - this is absolutely bizarre, surely saved a lot of time thanks to this answer. – n13 Apr 28 '19 at 14:29
  • Thanks! Afternoon saver – Matthijs May 16 '19 at 14:33
  • Been trying out code suggestions on implementing preferredStatusBarStyle. This is the only one that works. Thanks! – arvinq May 30 '19 at 00:42
  • Where does one set this for navigation bars in storyboards? I can't seem to find it and it seems my view controller is probably being overwritten by this setting in the storyboard – Zack Shapiro Oct 03 '19 at 23:12
  • Thanks for the bs again Apple! Thanks for this solution matt! – Chris Allinson Apr 20 '20 at 00:39
  • Is it possible to tie this solution in with Appearance usage and cases when navigation bar is hidden? – eagle.dan.1349 Jun 22 '20 at 12:23
  • Thanks. But this is so confusing. So, when to use preferredStatusBarStyle? – Tibin Thomas Aug 21 '20 at 07:53
  • Should be in the `viewWillAppear` +1 – Codetard Sep 06 '20 at 17:56
36

If you choose a same status bar color for each View Controller:

<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>

Ad this to your Info.plist and set status bar color from Project -> Targets -> Status Bar Style by desired color.

On the other hand, in your case, you have a navigation controller which is embedded in a view controller. Therefore, you want to different status bar color for each page.

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

Ad this to your Info.plist. Then, create a custom class for your NavigationController. After that you can implement the method:

class LightContentNavigationController: UINavigationController {

    override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }
}

Thats it! Please, inform me whether this was useful!

Mazen Kasser
  • 3,559
  • 2
  • 25
  • 35
Oliver
  • 599
  • 6
  • 14
  • Someone deleted my comment! I'm putting it back: This resolved my issue, thabks very much - I was missing the entry in my Plist – Nostradamus Sep 24 '18 at 05:13
  • You really saved my life. Thank you so much – Habib Ali May 23 '19 at 00:16
  • This is the perfect answer. Thanks a lot! Main point is to subclass UINavigationController and not to add the extension of it. – Dhaval H. Nena Jul 16 '21 at 10:52
  • I have navigation controllers with hidden navigationbar that work with `preferredStatusBarStyle` directly, but those that have navigationbar had to have this subclass, tysm!! – leverglowh May 31 '23 at 14:07
6

If Matt's answer isn't working for you, try adding this line of code before you present your viewController.

viewController.modalPresentationCapturesStatusBarAppearance = true

I encountered a bug where setting modalPresentationStyle to overFullScreen does not give the status bar control to the presented view controller or navigation controller.

Micro
  • 10,303
  • 14
  • 82
  • 120
Jeffrey Chang
  • 433
  • 1
  • 7
  • 19
3

I was using navigation controller for each tab of UITabBarController. Subclassing UINavigationController and overriding childForStatusBarStyle fixed the issue for me.

class MyNavigationController: UINavigationController {
    open override var childForStatusBarStyle: UIViewController? {
        return topViewController?.childForStatusBarStyle ?? topViewController
    }
}
Adeel Miraj
  • 2,472
  • 3
  • 22
  • 32
2

If you have a modal UIViewController the situation becomes very tricky.

Short answer:

  1. Present modal using UIModalPresentationStyle.fullScreen
  2. override preferredStatusBarStyle (in your modal vc)
  3. call setNeedsStatusBarAppearanceUpdate() in viewWillAppear (in your modal vc)

If you don't want to use UIModalPresentationStyle.fullScreen you have to set modalPresentationCapturesStatusBarAppearance

According to apple doc:

When you present a view controller by calling the present(_:animated:completion:) method, status bar appearance control is transferred from the presenting to the presented view controller only if the presented controller's modalPresentationStyle value is UIModalPresentationStyle.fullScreen. By setting this property to true, you specify the presented view controller controls status bar appearance, even though presented non-fullscreen.

The system ignores this property’s value for a view controller presented fullscreen.

Levan Karanadze
  • 739
  • 1
  • 11
  • 21
0

You can set

vc.modalPresentationCapturesStatusBarAppearance = true

to make the customization works.

Santiago
  • 448
  • 3
  • 12
0

Customizing UINavigationController can fix the issue

class ChangeableStatusBarNavigationController: UINavigationController {

    override var preferredStatusBarStyle: UIStatusBarStyle {
        return topViewController?.preferredStatusBarStyle ?? .default
    }
}

Ref: https://serialcoder.dev/text-tutorials/ios-tutorials/change-status-bar-style-in-navigation-controller-based-apps/

Changwei
  • 672
  • 1
  • 5
  • 16