'Status bar issue in device dark mode

I am adding an option to add an option for users to choose system/light/dark modes.

I am storing user choice in user defaults. Below is my code in AppDelegate and custom UINavigationController class.

I have also tried to add customer UITabBarController with same code as customer UINavigationController. Added code.

The issue is when the device is in dark mode and the user has selected light mode then the status bar is not visible. Similarly, if the device is in light mode but the user has selected dark mode then the status bar is not white.

Additional information

Scenario - Device in dark mode and app style light App opens with status bar invisible. if i toggle device userInterfaceStyle to light then status bar text becomes black and visible The status bar becomes light and visible when i tap on another tab bar button to go to different view controller. The issue is only on first view controller when app opens. have added output of logging statements.

Tried solutions shown on some posts but was not able to get around.

enter image description here

AppDelegate

if let currentUserSelectedInterfaceStyle = userDefaults.string(forKey: "currentUserInterfaceStyle") {
    switch currentUserSelectedInterfaceStyle {
       case "light" :
           window?.overrideUserInterfaceStyle = UIUserInterfaceStyle.light
       case "dark" :
           window?.overrideUserInterfaceStyle = UIUserInterfaceStyle.dark
       case "system":
           window?.overrideUserInterfaceStyle = UIUserInterfaceStyle.unspecified
       default:
           window?.overrideUserInterfaceStyle = UIUserInterfaceStyle.unspecified
    }
}
else {
    userDefaults.set("light", forKey: "currentUserInterfaceStyle")
    userDefaults.synchronize()
    window?.overrideUserInterfaceStyle =  .light
}


Custom navigation controller class

is setting statusBarStyle to UIStatusBarStyle.default an issue? But I cannot set it to another value before the nav controller is instantiated.

class DarkModeAwareNavigationController: UINavigationController {
        
            var statusBarStyle =  UIStatusBarStyle.default { didSet
                {
                    setNeedsStatusBarAppearanceUpdate()
                }
            }
        
            override var preferredStatusBarStyle: UIStatusBarStyle {
                statusBarStyle
            }
            
            override open var childForStatusBarStyle: UIViewController? {
                return self.topViewController
            }
                
            override init(rootViewController: UIViewController) {
                super.init(rootViewController: rootViewController)
                updateStatusBarColor()
            }
        
            required init?(coder aDecoder: NSCoder) {
                super.init(coder: aDecoder)
                updateStatusBarColor()
            }
        
            override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
                super.traitCollectionDidChange(previousTraitCollection)
                if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
                      updateStatusBarColor()
                }
            }
        
        }
            
        func updateStatusBarColor() {
            
            let deviceStyle = UIScreen.main.traitCollection.userInterfaceStyle == .light ? "light" : "dark"
            let appStyle = traitCollection.userInterfaceStyle == .light ? "light" : "dark"
        
            switch UIScreen.main.traitCollection.userInterfaceStyle
            {
                case .unspecified:
                    statusBarStyle = .lightContent
                case .light:
                    statusBarStyle = .darkContent
                    logger.info("DarkNavVC device is \(deviceStyle) and app  is \(appStyle)")
                case .dark:
                    statusBarStyle = .lightContent
                    logger.info("DarkNavVC device is \(deviceStyle) and app  is \(appStyle)")
                default:
                    statusBarStyle = .lightContent
                }
                logger.info("DarkNavVC setting statusBarStyle to \(statusBarStyle)")
        
        }
     }
    
    
    class DarkModeAwareTabBarController: UITabBarController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
        }
        
        let userDefaults = UserDefaults.standard
                
        var statusBarStyle =  UIStatusBarStyle.default { didSet
            {
                setNeedsStatusBarAppearanceUpdate()
    
            }
    
        }
        override var preferredStatusBarStyle: UIStatusBarStyle {
            statusBarStyle
    
        }
        
        required init?(coder aDecoder: NSCoder) {
           super.init(coder: aDecoder)
            updateStatusBarColor()
        }
    
        override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
                  
            super.traitCollectionDidChange(previousTraitCollection)
                   
            if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
                  updateStatusBarColor()
            }
        }
        
        func updateStatusBarColor() {
            
            let currentUserSelectedInterfaceStyle = userDefaults.string(forKey: "currentUserInterfaceStyle")
            let appStyle = traitCollection.userInterfaceStyle == .light ? "light" : "dark"
    
            switch traitCollection.userInterfaceStyle
            {
                case .unspecified:
                    statusBarStyle = .lightContent
                case .light:
                    statusBarStyle = .darkContent
                    logger.info("DarkTabVC device  is \(deviceStyle) and app  is \(appStyle)")
                case .dark:
                    statusBarStyle = .lightContent
                    logger.info("DarkTabVC device  is \(deviceStyle) and app  is \(appStyle)")
                default:
                    statusBarStyle = .lightContent
    
            }
            logger.info("DarkTabVC setting statusBarStyle to \(statusBarStyle)")
    
        }
}


[AppDelegate.swift:129] application(_:didFinishLaunchingWithOptions:) > dark mode detected
[DarkModeAwareNavigationController.swift:140] updateStatusBarColor() > DarkNavVC device is dark and app  is dark
[DarkModeAwareNavigationController.swift:145] updateStatusBarColor() > DarkNavVC setting statusBarStyle to UIStatusBarStyle(rawValue: 1)
[DarkModeAwareNavigationController.swift:140] updateStatusBarColor() > DarkNavVC device is dark and app  is dark
[DarkModeAwareNavigationController.swift:145] updateStatusBarColor() > DarkNavVC setting statusBarStyle to UIStatusBarStyle(rawValue: 1)
[DarkModeAwareNavigationController.swift:140] updateStatusBarColor() > DarkNavVC device is dark and app  is dark
[DarkModeAwareNavigationController.swift:145] updateStatusBarColor() > DarkNavVC setting statusBarStyle to UIStatusBarStyle(rawValue: 1)
[DarkModeAwareNavigationController.swift:140] updateStatusBarColor() > DarkNavVC device is dark and app  is dark
[DarkModeAwareNavigationController.swift:145] updateStatusBarColor() > DarkNavVC setting statusBarStyle to UIStatusBarStyle(rawValue: 1)
[DarkModeAwareNavigationController.swift:140] updateStatusBarColor() > DarkNavVC device is dark and app  is dark
[DarkModeAwareNavigationController.swift:145] updateStatusBarColor() > DarkNavVC setting statusBarStyle to UIStatusBarStyle(rawValue: 1)
[DarkModeAwareTabBarController.swift:129] updateStatusBarColor() > DarkTabVC device  is dark and app  is dark
[DarkModeAwareTabBarController.swift:134] updateStatusBarColor() > DarkTabVC setting statusBarStyle to UIStatusBarStyle(rawValue: 1)
[DarkModeAwareNavigationController.swift:140] updateStatusBarColor() > DarkNavVC device is dark and app  is dark
[DarkModeAwareNavigationController.swift:145] updateStatusBarColor() > DarkNavVC setting statusBarStyle to UIStatusBarStyle(rawValue: 1)
[DarkModeAwareNavigationController.swift:140] updateStatusBarColor() > DarkNavVC device is dark and app  is dark
[DarkModeAwareNavigationController.swift:145] updateStatusBarColor() > DarkNavVC setting statusBarStyle to UIStatusBarStyle(rawValue: 1)
[DarkModeAwareNavigationController.swift:140] updateStatusBarColor() > DarkNavVC device is dark and app  is dark
[DarkModeAwareNavigationController.swift:145] updateStatusBarColor() > DarkNavVC setting statusBarStyle to UIStatusBarStyle(rawValue: 1)
[DarkModeAwareNavigationController.swift:140] updateStatusBarColor() > DarkNavVC device is dark and app  is dark
[DarkModeAwareNavigationController.swift:145] updateStatusBarColor() > DarkNavVC setting statusBarStyle to UIStatusBarStyle(rawValue: 1)
[DarkModeAwareNavigationController.swift:140] updateStatusBarColor() > DarkNavVC device is dark and app  is dark
[DarkModeAwareNavigationController.swift:145] updateStatusBarColor() > DarkNavVC setting statusBarStyle to UIStatusBarStyle(rawValue: 1)
[DarkModeAwareTabBarController.swift:129] updateStatusBarColor() > DarkTabVC device  is dark and app  is dark
[DarkModeAwareTabBarController.swift:134] updateStatusBarColor() > DarkTabVC setting statusBarStyle to UIStatusBarStyle(rawValue: 1)
[DarkModeAwareTabBarController.swift:126] updateStatusBarColor() > DarkTabVC device  is dark and app  is light
[DarkModeAwareTabBarController.swift:134] updateStatusBarColor() > DarkTabVC setting statusBarStyle to UIStatusBarStyle(rawValue: 3)
[DarkModeAwareNavigationController.swift:137] updateStatusBarColor() > DarkNavVC device is dark and app  is light
[DarkModeAwareNavigationController.swift:145] updateStatusBarColor() > DarkNavVC setting statusBarStyle to UIStatusBarStyle(rawValue: 3)


Solution 1:[1]

Try this, it's what I'm using in my application to change the status bar text color:

AppDelegate:

extension UIApplication {
    func switchHostingController() -> Void {
        if (appThemeType == "dark") {
            windows.first?.rootViewController = DarkHostingController(rootView: ContentView())
        } else {
            windows.first?.rootViewController = LightHostingController(rootView: ContentView())
        }
    }
}

class DarkHostingController<ContentView>: UIHostingController<ContentView> where ContentView : View {
    override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }
}

class LightHostingController<ContentView>: UIHostingController<ContentView> where ContentView : View {
    override var preferredStatusBarStyle: UIStatusBarStyle {
        return .darkContent
    }
}

Keep in mind that appThemeType is just a placeholder variable. Let me know if this works for you :)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Amy