I'm currently developing an app (in Swift 3) on Xcode 8 beta, for iOS 10.
What I want to achieve is to change status bar style within a view controller at run time, for changing the theme from daytime theme to night theme.
I've found out that the method I used to use when I was developing another app in the past was deprecated, as shown here on the API reference.
However, preferredStatusBarStyle won't work here since I would like to change it within a single view controller.
Can anybody think of other ways to perform this?
Thanks in advance
EDIT:
To be clear, what I want to do is to change the style when the view controller is already on screen.
You can create a statusBarStyle variable that when changed updates the status bar appearance. If you only want this to affect one controller, simply reverse the effect when the Controller will or did disappear.
var statusBarStyle: UIStatusBarStyle = .lightContent {
didSet {
setNeedsStatusBarAppearanceUpdate()
}
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return statusBarStyle
}
The above solution will override the previous controller's status bar style before the controller appears. If you want to change the status bar style when the controller appears, try this:
var statusBarStyle: UIStatusBarStyle? {
didSet {
setNeedsStatusBarAppearanceUpdate()
}
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return statusBarStyle ?? super.preferredStatusBarStyle
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
statusBarStyle = .lightContent
}
In your info.plist, add the UIViewControllerBasedStatusBarAppearance key with a value of false.
Then, in your viewController when switching to your night theme:
UIApplication.shared.statusBarStyle = .lightContent
To go back to black:
UIApplication.shared.statusBarStyle = .default
Related
This question already has answers here:
preferredStatusBarStyle var not working in iOS12?
(7 answers)
Closed 3 years ago.
One of my Controller is having navigation status bar color is black, I want to make it white. how can I change it?
As some people already suggested, inside your viewController set:
override var preferredStatusBarStyle: UIStatusBarStyle { return .lightContent }
But, this is not enough. Since that viewController is contained inside UINavigationController, you need to say to nav controller to use status bar style based on currently displayed controller. One way to do this is by extending UINavigationController like this:
extension UINavigationController {
open override var preferredStatusBarStyle: UIStatusBarStyle {
return topViewController?.preferredStatusBarStyle ?? .default
}
}
The preferredStatusBarStyle property is set to lightContent. Build and Run the project to see the content of the status bar changed to light.
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
The content of the status bar is dark again, which is the default. The reason for this is, iOS asked for the style of the status bar of the navigation controller instead of the contained view controller.
To change the style of the navigation controller to lightinside the app, add the following viewDidAppear(_:) method
override func viewDidAppear(_ animated: Bool) {
navigationController?.navigationBar.barStyle = .black
}
Add viewWillAppear to your code
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let statusBar: UIView = UIApplication.shared.value(forKey: "statusBar") as! UIView
if statusBar.responds(to:#selector(setter: UIView.backgroundColor)) {
statusBar.backgroundColor = UIColor.white
}
let img = UIImage()
navigationController?.navigationBar.shadowImage = img
navigationController?.navigationBar.setBackgroundImage(img, for: UIBarMetrics.default)
navigationController?.navigationBar.backgroundColor = UIColor.white
navigationController?.navigationBar.barTintColor = UIColor.white
}
By default we can set Status bar Style in our project plist but if you want to define color for specific controller then we should override following method in your controller class .
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
Hope it will help you :)
Call this inside your ViewController:
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
Updated for Swift 5:
override var preferredStatusBarStyle: UIStatusBarStyle {
.lightContent
}
Also, if you don't already have made it, you should set the View controller-based status bar appearance property from your info.plist file to YES.
Just downloaded the new xCode 10.0 and saw that the old statusBarStyle has been deprecated since iOS 9.0.
Warning: Setter for 'statusBarStyle' was deprecated in iOS 9.0: Use -[UIViewController preferredStatusBarStyle]
Deprecated code:
UIApplication.shared.statusBarStyle = .default
I tried using self.preferredStatusBarStyle, but found out the property is only a getter. So anyone knows how to set the statusBarStyle?
Edit
I want to change the statusBarStyle inside a function, where a user can switch between different themes. For example:
func changeStatusBar(toDarkMode: Bool) {
if toDarkMode {
// Set to light statusBarStyle
} else {
// Set to default
}
}
Add View controller-based status bar appearance NO in Info.plist
And select Light in Status Bar Style in Deployment Info
Set your darkMode variable using the same code you have now, then use it in the computed variable that the system is expecting:
var darkMode = false
override var preferredStatusBarStyle : UIStatusBarStyle {
return darkMode ? .default : .lightContent
}
Depending on the context you may need to force a refresh of the screen for it to take effect. You would do that with the following call:
setNeedsStatusBarAppearanceUpdate()
In swift4, You can use this block of code below viewDidLoad() in your ViewController-
override var preferredStatusBarStyle : UIStatusBarStyle {
return .lightContent
}
If you use UINavigationController you also may want to use following code :
extension UINavigationController {
open override var preferredStatusBarStyle: UIStatusBarStyle {
return topViewController?.preferredStatusBarStyle ?? .default
}
}
Reason is setNeedsStatusBarAppearanceUpdate() doesn't call childs preferredStatusBarStyle
None of the other suggestions worked for me. I ended up getting it to work by:
Setting:
override var preferredStatusBarStyle : UIStatusBarStyle {
return .lightContent
}
Calling:
setNeedsStatusBarAppearanceUpdate()
My solution was as this:
making an extension from the navigation controller:
extension UINavigationController {
open override var preferredStatusBarStyle: UIStatusBarStyle {
if let topViewController = presentedViewController{
return topViewController.preferredStatusBarStyle
}
if let topViewController = viewControllers.last {
return topViewController.preferredStatusBarStyle
}
return .default
}
}
and if you have a viewController that will have another style than the style of the app , you can make this
var barStyle = UIStatusBarStyle.lightContent
override var preferredStatusBarStyle: UIStatusBarStyle{
return barStyle
}
lets say that you app status style is .default and you want this screen to be .lightContent
so barStyle will take the .lightContent as its default value, this will change the status bar style to lightContent, and then make sure when viewWillDisappear change the barStyle again to the app status bar style which in our case is .default .
this is works for me
Since UIApplication.shared.setStatusBarStyle(.default, animated: true) is deprecated from IOS9 is it possible to change status bar style with animation on push? I cannot find any description in docs.
It's now a variable you have to override:
override var preferredStatusBarStyle: UIStatusBarStyle
override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation
Depending on when you update the status bar, you might also have to call setNeedsStatusBarAppearanceUpdate()
If you want to set status bar style, application level then set UIViewControllerBasedStatusBarAppearance to NO in your .plist file.
if you wan to set status bar style, at view controller level then follow these steps:
Set the UIViewControllerBasedStatusBarAppearance to YES in the .plist file, if you need to set status bar style at UIViewController level only.
In the viewDidLoad add function - setNeedsStatusBarAppearanceUpdate
override preferredStatusBarStyle in your view controller.
-
override func viewDidLoad() {
super.viewDidLoad()
self.setNeedsStatusBarAppearanceUpdate()
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
Set value of .plist according to status bar style setup level.
To tackle the animation part the way I made it transition smoothly between .lightContent and .default was to use something similar to below each time you change it.
UIView.animate(withDuration: 0.2) {
self.setNeedsStatusBarAppearanceUpdate()
}
Place that in your VC you want the status bar to animate and you'll have a nice smooth animation.
override var preferredStatusBarStyle: UIStatusBarStyle {
return lightStatusBar ? .lightContent : .default
}
Above is a snippet of me changing the content based on a condition I have.
I'm writing an iOS App with multiple views. I've set the App to use ViewController-based status bar style, which allows me to use the following code
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
That worked like expected.
But then I've embedded the views in a navigation controller and connected a BarButtonItem with a showSegue. Since then the ViewController of the view switched to ignores the style settings and shows the default black status bar.
When you're in a navigation controller that will not get called. The navigation controller's preferredStatusBarStyle will be called. Try this along with your code:
extension UINavigationController {
open override var preferredStatusBarStyle: UIStatusBarStyle {
return topViewController?.preferredStatusBarStyle ?? .default
}
}
There is a solution that is a bit more concise (and recommended by Apple):
extension UINavigationController {
override open var childForStatusBarStyle: UIViewController? {
return topViewController
}
}
I'm finding it hard to change the status bar style programatically.
I see how to statically set it for each ViewController using a combo of (in ViewController.swift):
override var preferredStatusBarStyle: UIStatusBarStyle {
return UIStatusBarStyle.default
}
and (in info.plist):
View controller-based status bar appearance = YES
...
I'm looking to change it whenever I want!
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)
}
swift 3
1.Change in info.plist the row View controller-based status bar appearance and set it to NO
2.Change in appDelegate.swift in didFinishLaunchingWithOptions
UIApplication.shared.statusBarStyle = .lightContent
Store the status bar style as a property in your view controller:
var statusBarStyle: UIStatusBarStyle = .default
And then implement preferredStatusBarStyle in the same view controller:
override var preferredStatusBarStyle: UIStatusBarStyle {
return statusBarStyle
}
Then when you change statusBarStyle make sure to also call setNeedsStatusBarAppearanceUpdate. The preferredStatusBarStyle method is automatically called when the view appears/disappears, but if you change the status bar style while your view is visible, you have to tell the view controller the status bar appearance needs updating.
Note you still need to make the changes to the plist, and if your view controller is in a navigation controller, you may need to handle the status bar changes there instead (via a UINavigationController subclass, for example).
UIApplication.shared.setStatusBarStyle(…) was deprecated in iOS 9.0, so don't use that.