UIStatusBarStyle doesn't change - swift

I'm working on a swift app and I wanna change the UIStatusBarStyle according to the app's theme (there are 2 options - light and dark theme). I have set View controller-based status bar appearance to NO in the info.plist and in the UIViewController I tried to set it based on the current theme like so:
override var preferredStatusBarStyle: UIStatusBarStyle {
return Theme.current.statusBarStyle
}
protocol ThemeProtocol {
// Status Bar
var statusBarStyle: UIStatusBarStyle { get }
}
class Theme {
static var current: ThemeProtocol = LightTheme()
}
class LightTheme: ThemeProtocol {
// Status Bar
var statusBarStyle: UIStatusBarStyle = .default
}
class DarkTheme: ThemeProtocol {
// Status Bar
var statusBarStyle: UIStatusBarStyle = .lightContent
}
No result really. I tried to test it by returning only: return .lightContent but that didn't change the status bar either.
What am I doing wrong?
UPDATE:
Okay, so this is what I'm trying to do and it's not working.
fileprivate func applyTheme() {
statusBarStyle = UserDefaults.standard.bool(forKey: SelectedThemeKey) ? .default : .lightContent
self.setNeedsStatusBarAppearanceUpdate()
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return statusBarStyle
}
And it's not working. Despite changing the theme, the status bar always remain with the default style. applyTheme() is called in viewDidLoad() and viewWillAppear()

You need to call this method after any change
setNeedsStatusBarAppearanceUpdate()
//
class ViewController: UIViewController {
var current = UIStatusBarStyle.default
#IBAction func changeClicked(_ sender: Any) {
current = current == .default ? .lightContent : .default
self.setNeedsStatusBarAppearanceUpdate()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return current
}
}

First of all, your code makes no sense. You say
I have set View controller-based status bar appearance to NO in the info.plist and in the UIViewController I tried to set it
So on the one hand you tell the runtime, do not listen to my view controller. Then you complain when the runtime doesn't listen to your view controller!
Second, keep in mind that your view controller gets no say in the status bar appearance unless it is the top-level view controller (or the top-level view controller deliberately defers to it). If your view controller is inside a navigation controller, for example, its statusBarStyle is completely irrelevant.

First
if you are trying to change StatusBarStyle with UIApplication.shared.statusBarStyle = .default, then you should set
View controller-based status bar appearance to be NO.
in this way, you need to control UIApplication.shared.statusBarStyle by yourself in everywhere; e.g viewWillAppear / viewWillDisappear.
but this method is deprecated after iOS 9.
Now I suggest you learn the new way:
please set View controller-based status bar appearance to be YES, and
override UIViewController's preferredStatusBarStyle to handle it.
override var preferredStatusBarStyle: UIStatusBarStyle {
return .default
}
but it still not working, why?
in your case, I guess that UIViewController is one of viewControllers of UINavigationController.
if you used UINavigationController, you should override preferredStatusBarStyle in UINavigationController.
maybe you will say that I need to set different status bar style with difference view controllers, it is okay.
Just override childForStatusBarStyle in UINavigationController like this
override var childForStatusBarStyle: UIViewController? {
return topViewController
}
then override preferredStatusBarStyle in UIViewController you want to change.
you can also make it by extension like this
extension UINavigationController {
override open var childForStatusBarStyle: UIViewController? {
return topViewController
}
}

Related

Can not override the preferredStatusBarStyle

In dark mode style, the status bar disappear cause of dark color.
I added the:
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
but the problem is, when I add the method in "viewDidLoad" I get the error:
override can only be specified in class member
any idea how to resolve this?
preferredStatusBarStyle is a member of the UIViewController class. What you want to do here is to override this class member. The snippet in your question have nothing to do in the viewDidLoad method and should be placed in your subclass body like this :
class YourViewController: UIViewController {
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
I am going to answer the question here, maybe it can help someone else:
After hours checking my codes, I found out that I have rootViewController which I used as a authentication then after the authentication user pass to TabbarViewController... which is not rootViewController, I added the:
preferredStatusBarStyle
To my rootViewController and it works.
View controller-based status bar appearance should be
YES

Using TabbarViewController the preferredStatusBarStyle not called

I have a TabbarViewController with different views, the problem is:
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
not called in any the of the views.
I have tried to add:
extension UITabBarController {
open override var childForStatusBarStyle: UIViewController? {
return selectedViewController?.childForStatusBarStyle ?? selectedViewController
}
}
extension UINavigationController {
open override var childForStatusBarStyle: UIViewController? {
return topViewController?.childForStatusBarStyle ?? topViewController
}
}
Nothing change, should I call this extension method in some where else?
You could try to add in to Info.plist expect adding some codes.
You can basically add this into your Info.plist
I had to create a class of UInavigation Controller then add this methods to the class and it start to work.
override open var childViewControllerForStatusBarStyle: UIViewController? {
return self.topViewController
}
override open var preferredStatusBarStyle : UIStatusBarStyle {
return topViewController?.preferredStatusBarStyle ?? .default
}

What is the correct way to manage statusBarStyle in Swift?

I've tried adding key UIViewControllerBasedStatusBarAppearance to true inside info.plist file and then added the below code inside UINavigationController class which holds several UIViewController classes.
class HomeNavigationController: UINavigationController {
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
}
But, it did not work.
I've also tried setting the barStyle property of navigationBar to .black but that too didn't work either.
Also looked up to https://stackoverflow.com/a/58203998/9180494, but that did not help as well.
Please NOTE: For UIViewController classes not embedded inside any UINavigationController , if I use computed property preferredStatusBarStyle, then it works.
Try in viewDidAppear() of UINavigationController class:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
navigationController?.navigationBar.barStyle = .black
}
Also add (in the same class as above):
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
#Anuranjan Bose Try this on your view did load,
override func viewDidLoad() {
super.viewDidLoad()
setNeedsStatusBarAppearanceUpdate()
}

Status back content update acting strangely iOS13

For some reason the status bar is not updating the content (.lightContent) in iOS13. It takes like a second to actually update. It is working correctly on iOS12.
I have added View controller-based status bar appearance in the info.plist
My Code:
public override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
UINavigationBar.appearance().isTranslucent = false
navigationController?.navigationBar.barTintColor = UIColor.darkGray
setNeedsStatusBarAppearanceUpdate()
}
override public var preferredStatusBarStyle: UIStatusBarStyle {
//Override all Bool
if (self.view.backgroundColor?.isLight())! {
return .default
} else {
return .lightContent
}
}
overrideUserInterfaceStyle = .dark
matt commented to override the interface style, I do not have enough rep to add a comment, but this is a way to override to dark mode. Another possibility is that there is an issue with self.view.backgroundColor?.isLight()and your background color.

Attempting to Change the UIStatusBar Tint Color

I am trying to change the UIStatusBar tint color in a specific UIViewController.
Here is my code:
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
self.setNeedsStatusBarAppearanceUpdate()
}
Nothing is happening.
On a UINavigationController, preferredStatusBarStyle is not called because its topViewController is preferred to self. So, to get preferredStatusBarStyle called on an UINavigationController, you need to change its childViewControllerForStatusBarStyle.
To do it for one UINavigationController:
class MyRootNavigationController: UINavigationController {
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
override var childViewControllerForStatusBarStyle: UIViewController? {
return nil
}
}
You can add an extension to UINavigationController:
extension UINavigationController {
open override var childForStatusBarStyle: UIViewController? {
return visibleViewController
}
}
Then for view controllers that you want a light status bar (white time, icons etc.), then override preferredStatusBarStyle:
override var preferredStatusBarStyle: UIStatusBarStyle {
return UIStatusBarStyle.lightContent
}
For a dark status bar, you don't have to do anything.
You may need to add "View controller-based status bar appearance" with a value of "YES" in your info.plist