Talk about recent research on dark theme adaptation for iOS (compatible with iOS 13 and below).
Apple started supporting dark mode at the system level in iOS 13, and now many apps support dark mode as well. There are plenty of mature open source implementations of Dark Mode, and there’s no reason for me to implement one myself. However, after investigating the implementation of related solutions, I found that there is still a solution that is lighter, less intrusive, more Apple style and with low learning and migration costs.
Solution overview: Native + replace Window rootViewController
The idea behind the plan is simple:
- Generate a color using the judgment of the system version
iOS 13
And above returns the dynamic colors supported by the systeminit(dynamicProvider: @escaping (UITraitCollection) -> UIColor)
.- Other lower-version systems use colors that correspond to themes set by the user.
- It also determines the version when switching
iOS 13
And later versions directly setwindow
的overrideUserInterfaceStyle
- Other lower versions initialize VC entirely and then set VC to
window
的rootViewController
The specific code is as follows
Set a swappable theme
In this step we set the number of topics to support
enum Theme: Int.CaseIterable {
case none = 0
case light = 1
case dark = 2
var title: String {
switch self {
case .none: return "Follow"
case .light: return "Light"
case .dark: return "Dark"}}@available(iOS 13.0.*)
var mode: UIUserInterfaceStyle {
switch self {
case .none: return .unspecified
case .light: return .light
case .dark: return .dark
}
}
}
Copy the code
Set the color/image
class Tools {
@UserDefaultStorage(keyName: "appTheme")
static var _style: Int? // This is used to store the UserDefaults property globally
static var style: Theme {
get { return Theme(rawValue: (_style ?? 0)) ?? .dark }
set { _style = newValue.rawValue }
}
/// Create color, the core method
static func makeColor(light: UIColor.dark: UIColor) -> UIColor {
if #available(iOS 13.0.*) {
return UIColor { $0.userInterfaceStyle = = .light ? light : dark }
} else {
return Tools.style = = .light ? light : dark
}
}
// create img, the core method
static func makeImage(light: UIImage.dark: UIImage) -> UIImage {
if #available(iOS 13.0.*) {
let image = UIImage()
image.imageAsset?.register(light, with: .init(userInterfaceStyle: .light))
image.imageAsset?.register(dark, with: .init(userInterfaceStyle: .dark))
return image
} else {
return Tools.style = = .light ? light : dark
}
}
Copy the code
Switch the theme
func changeTheme(theme: Theme) {
Tools.style = theme
guard let window = UIWindow.hl.getKeyWindow() else { return }
if #available(iOS 13.0.*) {
window.overrideUserInterfaceStyle = theme.mode
} else {
guard let rootVC = window.rootViewController else { return }
let tabbar = Tools.setTabVC(withIndex: self.index)
window.rootViewController = tabbar
}
}
Copy the code
Check global Settings at system startupstyle
attribute
Many products require the ability to switch between dark and day mode and not follow the system when using custom mode, so if this is required, you need to determine and set it at startup
func application(_ application: UIApplication.didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?)
-> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
// If it is iOS
if #available(iOS 13.0.*) {
window?.overrideUserInterfaceStyle = Tools.style.mode
}
window?.rootViewController = Tools.getTabVC(withIndex: 0)
window?.makeKeyAndVisible()
return true
}
Copy the code
Other mainstream Solutions
I have also seen some third-party libraries implemented by open source in the last few days of the subject survey. Let me give you my opinion on these libraries, which can also save people from detours in the future
RxTheme
- A product belonging to the Rx community whose solution implementation is based on
RxSwift
. - And the way to do that is through
Rx
The binding relationship of each view color is held by the view, and the theme color is changed after receiving the signal - Because its implementation is based on protocol, so if it is componentized development, all colors must be centrally managed in one component, and it is difficult for other components to add colors by extension.
- The library lacks many attributes of the extension, if you encounter a need and happens to be the library does not have the attributes of the corresponding secondary extension
SwiftTheme
SwiftTheme is a very classic theme scheme written in Swift.
- Property extensions are comprehensive, and there are few properties that the library does not take into account
- The way to do it is right
NSObject
Spread out aDictionary
Store properties that store all controls that have been set, and then when the user triggers the switchNotification
. ReceivedNotification
After theDictionary
Each property of each control is evaluated and reassigned - Because its implementation scheme is based on notification, in
view
There may be performance problems when there are many orders of magnitude
Summary of the program
Based on the comparison of the above several mainstream open source schemes, this scheme has the following advantages and disadvantages:
-
advantages
- Low code intrusion (cost of change)
- Performance pressure free
- No third-party library dependencies
- You can smoothly switch to iOS 13 in the future
- System-level animation
-
disadvantages
- Only dark and Bright mode is supported (other themes can be supported, but even iOS 13 + devices will need to use the replacement
rootViewController
“) - All views involving CGColor need to be implemented
traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?)
methods iOS 12
And the following systems need to be reset when switchingrootViewController
, so all the VC’s will be freed and rebuilt, i.e. the scene will be lost if other pages have logic in action
- Only dark and Bright mode is supported (other themes can be supported, but even iOS 13 + devices will need to use the replacement
Overall, this scenario amounts to a streamlined approach to implementing the theme.
Demo
Talk is cheap, show me the code!
Demo based on the idea of this article: github.com/HanleyLee/D…
The last
The author of this article is Hanley Lee, first published in Shining Journey. If you agree with this article, please Follow