Unable to change status bar style - ios

I have a UIViewController VC, which embedded in UINavigationController NAV. The NavigationController is embedded in UITabBarController TAB. Now, I need every view controller in my app but VC to have .default status bar style. VC has to have lightContent status bar style.
What I’ve done to achieve the desired effect:
Set View controller-based status bar appearance in Info.plist to YES.
Overriden preferredStatusBarStyle property for every view controller that can be displayed by NAV including VC.
Put setNeedsStatusBarUpdate() into viewDidLoad() of every view controller that can be displayed by NAV including VC.
Such an approach resulted in nothing.
Since TAB is initial view controller inside my Main.storyboard and everything is essentially displayed through it, I thought that maybe I can change status bar through it. So I’ve written the following inside TAB description:
// MARK: Status bar
///
private var requiredStatusBarStyle: UIStatusBarStyle = .default
//
override var preferredStatusBarStyle: UIStatusBarStyle { get { return self.requiredStatusBarStyle } }
///
func setStatusBarStyle(_ style: UIStatusBarStyle)
{
requiredStatusBarStyle = style
DispatchQueue.main.async
{
self.setNeedsStatusBarAppearanceUpdate()
}
}
And then invoked setStatusBarStyle method of TAB by every view controller that can be displayed by NAV including VC in viewWillAppear method. This resulted in nothing as well. Funny thing is invoking setStatusBarStyle inside TAB’s viewDidLoad does nothing too.
Well, if it's not TAB that is preventing me from changing style, maybe NAV is? So I've made the following extension:
struct UINavigationControllerExtensionKeys
{
static var UIStatusBarStyleKey: UInt8 = 0
}
extension UINavigationController
{
private var requiredStatusBarStyle: UIStatusBarStyle
{
get
{
guard let style = objc_getAssociatedObject(self, &UINavigationControllerExtensionKeys.UIStatusBarStyleKey) as? UIStatusBarStyle else
{
return .default
}
return style
}
set (style)
{
objc_setAssociatedObject(self, &UINavigationControllerExtensionKeys.UIStatusBarStyleKey, style, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
open override var preferredStatusBarStyle: UIStatusBarStyle { get { return self.requiredStatusBarStyle } }
func setStatusBarStyle(_ style: UIStatusBarStyle)
{
requiredStatusBarStyle = style
DispatchQueue.main.async
{
self.setNeedsStatusBarAppearanceUpdate()
}
}
}
And then invoked setStatusBarStyle method of NAV by every child view controller of it in viewWillAppear method. No luck as well.
It is obvious that I'm overcomplicationg things here. But for some reason answers poroposed here and here do not work for me. I am lost here people. Please help.

Now, I need every view controller in my app but VC to have .default
status bar style. VC has to have lightContent status bar style.
For me, you're merely giving yourself a headache with your approaches. Here's my take and it will be lot easier.
Make a LightBaseViewController: UIViewController or whatever base class name you want for all the viewControllers you want to have the light status bar, and put this in LightBaseViewController's viewWillAppear:
UIApplication.shared.statusBarStyle = .lightContent
Then of course make a DarkBaseViewController and make the status bar dark by making statusBarStyle property back to default.
UIApplication.shared.statusBarStyle = .default
Subclass either the dark or light base view controllers.
Finally, set this property to NO in your info.plist:
View controller-based status bar appearance
Hope this helps.

Related

iOS Swift TabBar status bar text color glitch half white half black

I'm trying to change the status bar text to white on some of the view controllers, but on a few others it still needs to be black. (so cannot change it globally for the whole app).
Everything works fine, except the first few seconds, when clicking on different tab bars, when there is a glitch, and half of the status bar text becomes black, instead of white. Then everything updates perfectly.
The structure is like this:
A tab bar controller with a few tabs, each tab containing a navigation controller, containing a view controller.
Having navigation controllers made it necessary to change the navigationController?.navigationBar.barStyle = .black to make it work.
After pressing a few times on tabs, it works fine.
First thing I did of course was to set to YES the View controller-based status bar appearance from the .plist
I also have override the preferredStatusBarStyle, using a boolean to set which view controllers should have the white or black status bar text:
override var preferredStatusBarStyle: UIStatusBarStyle {
return coloredNavigationBar ? .lightContent : .default
}
var coloredNavigationBar: Bool = true
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if coloredNavigationBar {
navigationController?.navigationBar.barStyle = .black
} else {
navigationController?.navigationBar.barStyle = .default
}
setNeedsStatusBarAppearanceUpdate()
}
The code pasted is from the base view controller used everywhere.
Yes! #matt was right, thank you. Indeed iOS gets confused when using a tabbar.
The solution was to add this to the TabBarController:
override public var childForStatusBarStyle: UIViewController? {
if let controller = selectedViewController as? UINavigationController {
return controller.visibleViewController
}
return selectedViewController
}

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

I am able to hide the status bar on the launch screen by setting Status bar is initially hidden to YES in Info.plist and then I want to show it on my first view controller with a .lightContent style.
However UIApplication.shared.statusBarStyle = .lightContent is deprecated since iOS 9 (so I don't want to use it) and using the following code give me a black status bar on my first view controller.
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
How can I change the status bar style when my first view controller load?
I am trying to find a global solution like UIApplication.shared.statusBarStyle = .lightContent since I don't really want to set the status bar style for every view controller.
I have tested the solutions with View controller-based status bar appearance set to YES and NO.
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.

Preferred status bar style of view controller is ignored when in navigation controller

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
}
}

iOS set statusbar white, and hide in another ViewController

I need a white status bar for my main initial ViewController, but also be able to hide it in another ViewController. I can do one or the other, but not both at the same time. Any suggestions?
I set it to white by setting
View controller-based status bar appearance key to NO in the
Info.plist
override func preferredStatusBarStyle() -> UIStatusBarStyle {
return .LightContent
}
And to hide it (on another ViewController presented modally) I do,
override func prefersStatusBarHidden() -> Bool {
return statusBarHidden
}
however it won't hide unless I remove the key I previously added to the Info.plist, but if I remove the key, then the status bar goes back to black.
EDIT-MY Solution:
The View controller classes were not working in my case because I have the main view controller embedded in a navigation controller, my fix was to override the same methods but for the navigation controller instead of the view controller in question.
extension UINavigationController {
public override func preferredStatusBarStyle() -> UIStatusBarStyle {
return .LightContent
}
}
If you add
View controller-based status bar appearance key to NO in the Info.plist
You should use [UIApplication setStatusBarHidden:withAnimation:] and [UIApplication setStatusBarStyle:animated:] to change to the statusbar's appearance. Your method won't be called
As it is said in apple's document:
UIViewControllerBasedStatusBarAppearance (Boolean - iOS) Specifies whether the status bar appearance is based on the style preferred by the view controller that is currently under the status bar. When this key is not present or its value is set to YES, the view controller determines the status bar style. When the key is set to NO, view controllers (or the app) must each set the status bar style explicitly using the UIApplication object.
UIViewControllerBasedStatusBarAppearance key is the same as View controller-based status bar appearance key.
If you don't add the key,your method should work. try add both methods in these two Viewcontrollers, and add some breakpoint to see they're called or override by mistake.
The code in Swift 3.0 Xcode 8.2 works for me:
override open var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
override open var prefersStatusBarHidden: Bool {
return true
}

Status Bar Style - Swift 3 - change at any time

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.

Resources