'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.
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 |