1

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:

  1. Set View controller-based status bar appearance in Info.plist to YES.
  2. Overriden preferredStatusBarStyle property for every view controller that can be displayed by NAV including VC.
  3. 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.

Igor Andreev
  • 177
  • 1
  • 8
  • first of all, `setNeedsStatusBarUpdate` takes into account your current view controller that is presented. so if you call it in `viewDidLoad`, I would expect that at that moment the view controller is not yet presented, thus the status bar style of the presenting view controller will be used.. – Milan Nosáľ Mar 13 '18 at 13:40
  • second, your second approach seems to be like hacking it, which I would not recommend.. which ios versions are you supporting? don't you happen to have another window overlaying current screen (I had a problem like this)? – Milan Nosáľ Mar 13 '18 at 13:42
  • @MilanNosáľ I am supporting iOS 11 only. I am using `LNPopupController` to display popups through **TAB**. It doesn't matter whether popup is displayed though: status bar style is `.default` at all times. – Igor Andreev Mar 13 '18 at 13:59

1 Answers1

3

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.

  1. 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
    
  2. Then of course make a DarkBaseViewController and make the status bar dark by making statusBarStyle property back to default.

    UIApplication.shared.statusBarStyle = .default
    
  3. Subclass either the dark or light base view controllers.

  4. Finally, set this property to NO in your info.plist:

    View controller-based status bar appearance
    

Hope this helps.

Glenn Posadas
  • 12,555
  • 6
  • 54
  • 95