23
votes

I want to change the status bar style on a per-ViewController level on iOS 13. So far I didn't have any luck.
I define UIUserInterfaceStyle as Light in info.plist (as I do not want to support dark mode) and set UIViewControllerBasedStatusBarAppearance to true. preferredStatusBarStyle is called on my ViewController but completely ignored. The UIUserInterfaceStyle seems to always override the VC preferences. How do I get per-ViewController status bar style working on iOS 13? Or is it not supported any more?

5
It should work. The one from plist is used before the app is loaded (when splash screen is shown). The rest should be defined with preferredStatusBarStyle for each of the view controllers. Note that only top view controllers matter, not embedded ones. So it will work with controller you present but not with controller you for instance push on your navigation controller. To make navigation controller work as well you will need to subclass it forward the setting.Matic Oblak
And this is without setting any option in the plist at all. These are default settings.Matic Oblak
Yes, it's in a TabBarController that holds NavigationBarControllers, but I already have extensions in place to deal with that. extension UITabBarController { open override var childForStatusBarStyle: UIViewController? { return selectedViewController?.childForStatusBarStyle ?? selectedViewController } } extension UINavigationController { open override var childForStatusBarStyle: UIViewController? { return topViewController?.childForStatusBarStyle ?? topViewController } } As I said, preferredStatusBarStyle is called but just ignored.Micky
@MaticOblak What compounds the problem is when you modal segue to a ViewController (or NavController) that's not full-screen, so is the modal cards UI of iOS 13 kick in. Now the status bar is owned by a view controller in Apple's control, so there's no way to subclass it! How can we control the status bar light/dark at that time? That ViewController tries to follow dark mode regardless of what I do.Smartcat
I am facing the same problem - Are you setting the window in the AppDelegate? I implemented a SceneDelegate and the statusbar now works as expected. The problem is this means I have a lot of @available(iOS 13.0, *) code and I have to implement the AppDelegate methods again.DoesData

5 Answers

17
votes

iOS 13.2, Swift 5.1

For me nothing worked from solutions mentioned before. After 5 hours I ended up on modalPresentationCapturesStatusBarAppearance flag .

    destinationNavigationController.modalPresentationCapturesStatusBarAppearance = true
    sourceViewController.present(destinationNavigationController, animated: animated, completion: nil)

After this preferredStatusBarStyle was called in presented VC.

override var preferredStatusBarStyle: UIStatusBarStyle {
    if #available(iOS 13.0, *) {
        if traitCollection.userInterfaceStyle == .light {
            return .darkContent
        } else {
            return .lightContent
        }
    } else {
        return .lightContent
    }
}
3
votes

I had the same issue on iOS13 while it was fine on iOS12 for my app. I have a TabBarController which holds 3 NavigationBarControllers, and I present TabBarController from a previous ViewController. I fixed it by setting .modalPresentationStyle to .fullScreen when presenting:

tabbarController.modalPresentationStyle = .fullScreen

Maybe it will help you somehow...

3
votes

In iOS13, there is now a .darkContent option for UIStatusBarStyle. For black text, use this (instead of .default) for preferredStatusBarStyle.

2
votes

In my case, I had a similar issue with incorrect UIStatusBarStyle. For some view controllers in my app, I need to set a dark status bar style ignoring current system color mode. The problem was I used .default value, but in iOS 13 it changes depending on the context. That's why I added a small workaround to handle both iOS 12- and iOS 13+ cases.

private extension UIStatusBarStyle {

    static var darkContentWorkaround: UIStatusBarStyle {
        if #available(iOS 13.0, *) {
            return .darkContent
        } else {
            return .default
        }
    }

}
0
votes

i had the same problem on iOS 13 while using navigation controller i was able to change the status bar color using

let navBarAppearance = UINavigationBarAppearance()

navigationBar.scrollEdgeAppearance = navBarAppearance

but the problem was when i was using present controller the status bar didn't change i used this code on top view controller

override func viewDidAppear(_ animated: Bool) {

    if #available(iOS 13, *)
    {
        let statusBar = UIView(frame: (UIApplication.shared.keyWindow?.windowScene?.statusBarManager?.statusBarFrame)!)
        statusBar.backgroundColor = UIColor.systemBackground
        UIApplication.shared.keyWindow?.addSubview(statusBar)
    }
}

you can use your color in "UIColor.systemBackground"