Updating the Status Bar Style Between View Controllers

Updating the status bar style between view controllers

There is a great deal of misunderstanding promulgated about how to govern the status bar style when your view controller is a child of a navigation controller.

Your child view controllers can implement preferredStatusBarStyle, and this will work correctly if the navigation bar is hidden.

If the navigation bar is showing, the navigation controller sets the status bar style based on the navigation bar's barStyle — to .default if the bar style is .default, and to .lightContent if the bar style is .black. So the correct way for your view controller to set the status bar style, when the navigation bar is showing, is to set the navigation controller's navigation bar style.

The obvious place to do this is in viewWillAppear, which is called whenever this view controller becomes the top of the navigation controller's stack:

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.navigationBar.barStyle = .black // or .default
}

How to change the status bar style when a view controller is loading?

The problem you're experiencing is that UINavigationController doesn't defer the choice of status bar to its view controllers.

Instead, for a navigation controller, the status bar style can be set by adjusting the barStyle property of its navigationBar.

If it is set to a black style, then the status bar will be light style:

navigationController?.navigationBar.barStyle = .black

Note, that this will also change the color of the navigationBar, however you can still set the bar's colour to whatever you want using barTintColor:

navigationController?.navigationBar.barTintColor = .purple

If you want to make a global change, so that all instances of UINavigationController use the same status bar style (useful if you've got multiple tabs all of which use a navigation controller), then you can add an extension on UINavigationController and override the preferredStatusBarStyle property:

extension UINavigationController {
open override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
}

A final option, is to defer the choice to the view controllers in the navigation controller's stack.

To do that, override the childViewControllerForStatusBarStyle property of your navigation controller extension and have it return the topViewController:

extension UINavigationController {
open override var childViewControllerForStatusBarStyle: UIViewController? {
return topViewController
}
}

In this case, you'll need to override preferredStatusBarStyle in all of your view controllers (not the optimal approach, but it's an option if you need this granular level of control on a per-child-controller basis).

All of these solutions require that your View controller-based status bar appearance key in Info.plist is set to YES.

Is it possible to change Status Bar color for all view controllers?

Set the style of the status bar in AppDelegate.swift:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
UIApplication.shared.statusBarStyle = .lightContent

return true
}

And add the following code to your Info.plist:

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

How to update the status bar style when transitioning to a new view controller?

Ensure that UIViewControllerBasedStatusBarAppearance is set to YES in your Info.plist file. This should ensure that the preferredStatusBarStyle is called per view controller.

Failing that, set the above plist key to NO, then add the following to viewWillAppear in each of your UIViewController's implementation files:

if ([self respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) {
[self setNeedsStatusBarAppearanceUpdate];
}

You will need to ensure that this is implemented in every view controller in which you need to update the appearance of the status bar.

If all else fails

Call the following from wherever you want to update the status bar style:

[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];

Obviously replacing the style with your desired status bar style.

Hope this helps!

Swift 4 - Specific View Controller status bar style not changing

Your UINavigationController is the one setting the preferredStatusBarColor. I bet if you tried presenting this VC instead of pushing it to the navigation controller you'd see the light statusbar style.

What you'll probably want to do instead is implement a custom navigation controller and override preferred status bar style.

class CustomNavController: UINavigationController {
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent;
}
}

EDIT:

Based on comments what you're probably looking to do is set the preferred status bar color to whatever ViewController is the top most of the UINavigationController. Here's an extension that does that, with this extension you no longer need the CustomNavController class above, just used a regular UINavigationController. You will also need to override the preferred status bar style in each of your view controllers. Credit to this SO question, see here for more in depth discussions on statusbarstyle and navigation controllers: preferredStatusBarStyle isn't called

extension UINavigationController {
open override var childViewControllerForStatusBarStyle: UIViewController? {
return self.topViewController
}

open override var childViewControllerForStatusBarHidden: UIViewController? {
return self.topViewController
}
}

Changing the Status Bar Color for specific ViewControllers using Swift in iOS8

After reading all the suggestions, and trying out a few things, I could get this to work for specific viewcontrollers using the following steps :

First Step:

Open your info.plist and insert a new key named "View controller-based status bar appearance" to NO

Second Step (Just an explanation, no need to implement this):

Normally we put the following code in the application(_:didFinishLaunchingWithOptions:)
method of the AppDelegate,

Swift 2

UIApplication.sharedApplication().statusBarStyle = .LightContent

Swift 3

UIApplication.shared.statusBarStyle = .lightContent

but that affects the statusBarStyle of all the ViewControllers.

So, how to get this working for specific ViewControllers - Final Step:

Open the viewcontroller file where you want to change the statusBarStyle and put the following code in viewWillAppear(),

Swift 2

UIApplication.sharedApplication().statusBarStyle = .LightContent

Swift 3

UIApplication.shared.statusBarStyle = .lightContent

Also, implement the viewWillDisappear() method for that specific viewController and put the following lines of code,

Swift 2

override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
UIApplication.sharedApplication().statusBarStyle = UIStatusBarStyle.Default

}

Swift 3

override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
UIApplication.shared.statusBarStyle = UIStatusBarStyle.default
}

This step will first change the statusBarStyle for the specific viewcontroller and then change it back to default when the specific viewcontroller disappears. Not implementing the viewWillDisappear() will change the statusBarStyle permanently to the new defined value of UIStatusBarStyle.LightContent

How to set Status Bar Style in Swift 3

[UPDATED] For Xcode 10+ & Swift 4.2+

This is the preferred method for iOS 7 and higher

In your application's Info.plist, set View controller-based status bar appearance to YES.

Override preferredStatusBarStyle (Apple docs) in each of your view controllers. For example:

override var preferredStatusBarStyle: UIStatusBarStyle {     
return .lightContent
}

If you have preferredStatusBarStyle returning a different preferred status bar style based on something that changes inside of your view controller (for example, whether the scroll position or whether a displayed image is dark), then you will want to call setNeedsStatusBarAppearanceUpdate() when that state changes.

iOS before version 7, deprecated method

Apple has deprecated this, so it will be removed in the future. Use the above method so that you don't have to rewrite it when the next iOS version is released.

If your application will support In your application's Info.plist, set View controller-based status bar appearance to NO.

In appDelegate.swift, the didFinishLaunchingWithOptions function, add:

UIApplication.shared.statusBarStyle = .lightContent

For Navigation Controller

If you use a navigation controller and you want the preferred status bar style of each view controller to be used and set View controller-based status bar appearance to YES in your application's info.plist

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

How to change status bar style - iOS 12

Set View controller-based status bar appearance to NO in the info.plist and override preferredStatusBarStyle in each view controller like so:

override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}

And call setNeedsStatusBarAppearanceUpdate() in your view controller (in viewDidLoad() for example).

Status Bar Style - Swift 3 - change at any time

Found the answer after quite a lot of digging!

Set (in info.plist):

View controller-based status bar appearance = NO

and remove the (in ViewController.swift):

override var preferredStatusBarStyle: UIStatusBarStyle {
return UIStatusBarStyle.default
}

...

Now you can use (in ViewController.swift):

UIApplication.shared.setStatusBarStyle(UIStatusBarStyle.lightContent, animated: true)

And, to initially set the style for each ViewController, use viewDidAppear:

override func viewDidAppear(_ animated: Bool) {
UIApplication.shared.setStatusBarStyle(UIStatusBarStyle.lightContent, animated: false)
}


Related Topics



Leave a reply



Submit