UIStatusBarStyle PreferredStatusBarStyle does not work on iOS 7
Solution 1
OK, here's the trick. You do have to add the key "View controller-based status bar" and set the value to No.
This is counter to what it appears the meaning of this key is, but even if you set the value to No
, you can still change the appearance of the status bar, and whether it shows or not in any view controller. So it acts like "Yes" but set it to "No"!
Now I can get the status bar white or dark.
Solution 2
I discovered that if your ViewController is inside a navigationController then the navigationController’s navigationBar.barStyle
determines the statusBarStyle.
Setting your navigationBar’s barStyle
to UIBarStyleBlackTranslucent
will give white status bar text (ie. UIStatusBarStyleLightContent
), and UIBarStyleDefault
will give black status bar text (ie. UIStatusBarStyleDefault
).
Note that this applies even if you totally change the navigationBar’s color via its barTintColor
.
Solution 3
For preferredStatusBarStyle()
to work within UINavigationController
and UITabBarController
I add the following code, which will get the preferred status bar style from the currently visible view controller.
extension UITabBarController {
public override func childViewControllerForStatusBarStyle() -> UIViewController? {
return selectedViewController
}
}
extension UINavigationController {
public override func childViewControllerForStatusBarStyle() -> UIViewController? {
return visibleViewController
}
}
For Swift 3 those are not methods but properties:
extension UITabBarController {
open override var childViewControllerForStatusBarStyle: UIViewController? {
return selectedViewController
}
}
extension UINavigationController {
open override var childViewControllerForStatusBarStyle: UIViewController? {
return visibleViewController
}
}
The Swift 4.2 properties have been renamed:
extension UITabBarController {
open override var childForStatusBarStyle: UIViewController? {
return selectedViewController
}
}
extension UINavigationController {
open override var childForStatusBarStyle: UIViewController? {
return visibleViewController
}
}
Usage
class ViewController: UIViewController {
// This will be called every time the ViewController appears
// Works great for pushing & popping
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
}
Solution 4
I may be coming to this a bit late, but incase anyone else is looking for a working and verified app wide solution.
@mxcl is correct in describing why this is happening. In order to correct it, we simply create an extension (or category in obj-c) that overrides the preferredSatusBarStyle() method of UINavigationController. Here is an example in Swift:
extension UINavigationController {
public override func preferredStatusBarStyle() -> UIStatusBarStyle {
if let rootViewController = self.viewControllers.first {
return rootViewController.preferredStatusBarStyle()
}
return super.preferredStatusBarStyle()
}
}
This code simply extracts the first view controller (the root view controller) and unwraps it (in obj-c just check that it is not nil). If the unwrap is successful (not nil) then we grab the rootViewControllers preferredStatusBarStyle. Otherwise we just return the default.
Hope this helps anyone who might need it.
Solution 5
To provide more detail into the accepted answer, put the following line in your app delegate's didFinishLaunchingWithOptions:
method:
[UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent;
Then, in your Info.plist, add View controller-based status bar appearance
and set it to NO
.
I believe that's how it should be done, NOT from the navigation controller, if you want the same status bar color for the entire app. You might have screens that are not necessarily embedded in a UINavigationController
, or a different UINavigationController
subclass somewhere else, and other things.
EDIT: You can also do it without typing any code: https://stackoverflow.com/a/18732865/855680
Related videos on Youtube
Andrew Smith
I've been writing audio test and measurement apps on iOS for 7 years now, and I'm still learning every day.
Updated on May 13, 2022Comments
-
Andrew Smith about 2 years
In my iPhone application built with Xcode 5 for iOS 7 I set
UIViewControllerBasedStatusBarAppearance=YES
ininfo.plist
, and in myViewController
I have this code:-(UIStatusBarStyle) preferredStatusBarStyle { return UIStatusBarStyleLightContent; }
But the status bar is still black against the black background.
I know its possible to change this app-wide by setting
UIViewControllerBasedStatusBarAppearance=NO
ininfo.plist
, but I actually need to alter this on aviewController
byviewController
basis at runtime.-
Noundla Sandeep over 9 yearsHi, I have the same issue like you mentioned in question. Did you get the solution? Please provide me that.
-
1218GG over 8 yearsYou can have a look at: Change applications status bar text color
-
-
Andrew Smith over 10 yearsThis does cause the preferredStatusBarStyle method to be called, but still the status bar is black.
-
User 1531343 over 10 yearsplease see my updated answer..let me know quickly if that works or not
-
Andrew Smith over 10 yearsMy original question explicitly says that I need to do view by view control of the status bar.
-
User 1531343 over 10 yearscan u please check your code with reference to my updated question?
-
Andrew Smith over 10 yearsI've edited the original post, to show what I am actually doing. Still not working. Again, I need to set UIViewControllerBasedStatusBarAppearance to NO.
-
User 1531343 over 10 yearsstackoverflow.com/questions/17678881/… please see this link
-
Andrew Smith over 10 yearsYes, that link agrees with me, it does not work unless you set UIViewControllerBasedStatusBarAppearance to NO and set the toolbar globally.
-
mxcl over 10 yearsDo you mean
[self setStatusBarNeedsUpdate]
in the second block? (Or something else at least). -
Nick over 10 yearsthis makes sense to me...great
-
mxcl over 10 yearsI believe it's because the
UINavigationController
’spreferredStatusBarStyle
doesn’t call through to the ViewController it hosts, and instead just returns based on its navigationBarStyle. -
Andrew Smith over 10 yearsIn this case the view is not inside a navigation controller.
-
joel.d over 10 yearsFor me this was wrong. The key needed to be set to "Yes", as you would expect. I'm on Xcode 5.1 iOS 7.1, so maybe it's changed.
-
Arjun Mehta over 10 yearsI'm using Xcode 5.1 and iOS 7.1 as well and NO worked for me... STRANGE.
-
Hadi Sharghi about 10 yearsWhere should I add this key?
-
Saren Inden almost 10 yearsIn your [AppName]-Info.plist file
-
bpolat almost 10 yearsIt works fine when "View controller-based status bar" key set to "YES" with Xcode6.0, iOS 8.0
-
Matej over 9 yearsVery counterintuitive to think that bar style takes preference over an implemented method in the view controller, and only when presenting modal views!
-
Thomás Pereira almost 9 yearsIn Swift 2.0 You must remove "as? UIViewController" of the condition statement.
-
Unome over 8 yearsBrilliant, I made one modification in addition to removing the "as" statement, I changed it from "first" to "last" this way whatever view controller is being seen by the user at the top of the stack will have the ability to control the color of the status bar. Awesome work, thanks for sharing!
-
bearMountain over 8 yearsIf your navigation controller doesn't have any view controllers, this would cause an infinite loop.
return self.preferredStatusBarStyle()
would call back into this exact same method. -
Benjamin over 8 yearsThis is the only one that worked for me and I have to say I DO find it counter intuitive.
-
Mohd Asim about 8 yearsSeems in iOS9 UIViewControllerBasedStatusBarAppearance by default contains value YES, as I needed to add it manually in .plist and set to NO to work properly.
-
Ric Santos about 8 yearsIn my case, instead of using the rootViewController, I used the topViewController as during the stack the style may change.
-
Thanh-Nhon Nguyen almost 8 years
UIBarStyleBlackTranslucent
is deprecated, useUIBarStyleBlack
instead -
Kesava almost 8 yearsThis is by far the best answer(For apps that use UINavigationController or UITabBarController
-
Admin almost 8 yearsThis post would be much improved if you could explain why and how this fixes the problem.
-
Cœur almost 8 years@Unome
visibleViewController
would be even better -
Unome almost 8 yearsPerfect! Thats even better @Cœur
-
Asad Ali over 7 yearsIt will work only if you set "View controller-based status bar" key to "YES". I tested on Xcode8.1, iOS10.1
-
Marcel Zanoni over 7 yearsFor me it worked with YES too, but only after setting it to NO and then back to YES first.
-
Kyle Begeman over 7 years@bearMountain We are returning from super, not self.
-
Scott Jungwirth about 7 yearsI ended up with the almost identical solution after struggling with this for hours.
-
AnBisw over 6 yearswhat is the usage for this?
-
Daniel Wood over 6 years@Annjawn these methods are used by UIKit. You don't need to do anything other than add it to your project.
-
AnBisw over 6 years@DanielWood yeah I figured that out and completely forgot that I used this exact same thing in one of my previous projects, although slightly differently.
-
wilforeal over 6 yearsInstead of subclassing UINavigationController you can also just create an extension for UINavigationController and achieve the same result without having to subclass.
-
ricks over 6 years2018 - navigationBar.barStyle = UIBarStyle.blackTranslucent
-
Andrew Plummer about 6 yearsAt some point this seems to have been fixed, just using preferredStatusBarStyle in each VC works fine for me now.
-
Jaime S about 6 yearsThe
UINavigationController
is a container view controller, as mentioned by @mxcl it uses itsdefault preferredStatusBarStyle
. There is achildViewControllerForStatusBarStyle
that is meant to be overridden by container view controller to provide the view controller for the preferred status bar style. In my opinion, theUINavigationController
should provide by default the top most pushed view controller as its default implementation. Anyway, you may need to subclass (or use a category) for the nav controller to customizechildViewControllerForStatusBarStyle
. -
nananta almost 6 yearsAppears the recommended way now is to set navigation bar to... "isTranslucent = true" and "barStyle = .black".
-
Musa almatri almost 6 yearsThis indeed the best answer
-
Supertecnoboff almost 6 years
[self setNeedsStatusBarAppearanceUpdate];
such a great method, thank you! -
P1xelfehler over 5 yearsYou can delete this key now as it is default in newer Xcode versions.
-
Mohamed Salah over 5 yearsNote that this way is deprecated from IOS 9.0
-
Arun Kumar almost 5 years@DanielWood Bravo!! upvoted your answer and this is by far well deserved. The only problem I'm having now is when I dismiss modally presented screen (that screen had a lighter status bar and after dismissing it the new screen has default/darker status bar) it changes the status bar to light.
-
Andrew Kirna over 4 yearsThis is a great answer pre iOS 13. However, this is now considered a "legacy customization" in iOS 13+. See my answer below 🙂
-
henrique over 4 yearsVery complete answer, thanks! Also, something I struggled for a while, on iOS 13 the
.default
style takes dark mode into consideration and it's not documented, so if you're also supporting previous iOS versions you can addif #available(iOS 13, *) { return .darkContent } else { return .default }
if you trying to setup the status bar style manually according to the color behind the status bar and that color is "bright". -
Marc Etcheverry over 4 yearsNote that the extension method of doing override var does not work anymore in Xcode 11.4/iOS 13.4
-
Marc Etcheverry over 4 yearsNote that the extension method of doing override var does not work anymore in Xcode 11.4/iOS 13.4
-
Marc Etcheverry over 4 yearsNote that the extension method of doing override var does not work anymore in Xcode 11.4/iOS 13.4
-
Vyacheslav over 4 years@MarcEtcheverry so, why did you downvote the answer? it seems strange.
-
Marc Etcheverry over 4 yearsBecause extending objective C classes in Swift is implemented through Objective C categories. Overriding methods through Objective C categories is not recommended and likely to break. See stackoverflow.com/a/38274660/2438634
-
Marc Etcheverry over 4 yearsThis is wrong and it breaks in iOS 13.4. Because extending objective C classes in Swift is implemented through Objective C categories. Overriding methods through Objective C categories is not recommended and likely to break. See stackoverflow.com/a/38274660/2438634
-
Marc Etcheverry over 4 yearsBecause extending objective C classes in Swift is implemented through Objective C categories. Overriding methods through Objective C categories is not recommended and likely to break. See stackoverflow.com/a/38274660/2438634
-
Marc Etcheverry over 4 yearsBecause extending objective C classes in Swift is implemented through Objective C categories. Overriding methods through Objective C categories is not recommended and likely to break. See stackoverflow.com/a/38274660/2438634
-
Vyacheslav over 4 years@MarcEtcheverry 'not recommended' != 'never use it!'. for jul2018 the answer was correct. Even this answer is not up-to-date this is not a reason to downvote it. I can't see the future
-
Igor Vasilev almost 4 yearsAlthough overriding the UINavigationController definitely works, it looks like a bug on Apple side that it doesn't do the childForStatusBarStyle by default returning its topViewController. Eg UITabBarController does this for its tabs. To me, there's no reason why UINavigationController, being a strictly container controller for hosting "real" View controllers rather than presenting its own UI, should "eat up" those status bar stylings. Will create a radar for Apple.