I have updated views in my app to support dark mode by adding
if #available(iOS 12.0, *) {
if self.traitCollection.userInterfaceStyle == .dark {
//Adapt to dark Bg
} else {
//Adapt to light Bg
}
}
Then, to allow for the case where the user backgrounds the app and returns to it after switching mode, I attach an observer in my viewDidLoad
if #available(iOS 12.0, *) {
NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
} else {
// Fallback on earlier versions
}
which triggers the function
@available(iOS 12.0, *)
@objc func willEnterForeground() {
if self.traitCollection.userInterfaceStyle == .dark {
print("App moving to foreground - dark")
//Adapt to dark Bg
} else {
print("App moving to foreground - light")
//Adapt to light Bg
}
}
However, self.traitCollection.userInterfaceStyle
still gives the old value so a full reload of the view is required to produce the desired update to the interface.
Using UIApplication.didBecomeActiveNotification
instead makes no difference.
You don't need all those messy if statements! Just add your colours to your Asset Catalogue and the right one will automatically be selected. This is similar to how you can add x1
, x2
and x3
images, and the right one will be selected.
Go to the Asset Catalogue and at the bottom left, click on the plus button, select "New Color Set":
Give the colour a name, and in the property inspector, set "Appearance" to "Any, Dark":
Choose a colour for each appearance:
Finally, use the UIColor(named:)
initialiser to initialise the colours and they will automatically change when the device's dark mode settings change:
someView.backgroundColor = UIColor(named: "myColor")
EDIT:
If the colours are only known at runtime, you can use the init(dynamicProvider:)
initialiser (iOS 13 only though):
someView.backgroundColor = UIColor {
traits in
if traits.userInterfaceStyle == .dark {
// return color for dark mode
} else {
// return color for light mode
}
}