在iOS中添加深色主题

大家好!

我叫Andrey,来自“我的经纪人”团队。我将告诉您ĸĸ在iOS中增加了对深色主题的支持。

苹果在iOS 13中为整个系统添加了深色主题,用户可以在iOS设置中选择浅色或深色外观。在暗模式下,系统对所有屏幕,视图,菜单和控件使用较暗的调色板。

图片

谁在乎-在猫下面。

深色设计支持


默认情况下,在Xcode 11中创建的应用程序在iOS 13中支持深色设计。但是,要完全实现深色模式,您需要进行其他更改:

  • 颜色应支持浅色和深色设计
  • 图像应支持明暗设计

苹果增加了支持浅色和深色设计的几种系统颜色。
图片

在iOS 13中,引入了新的UIColor初始化器

init (dynamicProvider: @escaping (UITraitCollection) -> UIColor)

添加静态功能来创建颜色,并支持在明暗设计之间进行切换:

extension UIColor {
    
    static func color(light: UIColor, dark: UIColor) -> UIColor {
        if #available(iOS 13, *) {
            return UIColor.init { traitCollection in
                return traitCollection.userInterfaceStyle == .dark ? dark : light
            }
        } else {
            return light
        }
    }
}

CGColor不支持在明暗之间自动切换。更改设计后,必须手动更改CGColor

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)
        
    layer.borderColor = UIColor.Pallete.black.cgColor
}

也可以为资源中的深色装饰添加颜色。

图片

但是我更喜欢在代码中添加颜色。

UIColor.Pallete
extension UIColor {
    
    struct Pallete {

        static let white = UIColor.color(light: .white, dark: .black)
        static let black = UIColor.color(light: .black, dark: .white)

        static let background = UIColor.color(light: .white, dark: .hex("1b1b1d"))
        static let secondaryBackground = UIColor(named: "secondaryBackground") ?? .black

        static let gray = UIColor.color(light: .lightGray, dark: .hex("8e8e92"))

    }
}


对于图像,只需在资源中添加用于黑暗设计的图像变体即可。

图片

让我们以一个小应用程序为例。


该应用程序将包含两个窗口和三个屏幕。

第一个窗口:授权屏幕。

第二个窗口:功能区屏幕和用户配置文件屏幕。

深色和深色设计中的屏幕截图
图片 图片 图片
图片 图片 图片

切换明暗主题


为该主题创建一个枚举:


enum Theme: Int, CaseIterable {
    case light = 0
    case dark
}

我们添加了存储当前主题的功能,以便在重新启动应用程序后将其还原。

extension Theme {
    
    //   UserDefaults
    @Persist(key: "app_theme", defaultValue: Theme.light.rawValue)
    private static var appTheme: Int
    
    //    UserDefaults
    func save() {
        Theme.appTheme = self.rawValue
    }
    
    //   
    static var current: Theme {
        Theme(rawValue: appTheme) ?? .light
    }
}

坚持
@propertyWrapper
struct Persist<T> {
    let key: String
    let defaultValue: T
    
    var wrappedValue: T {
        get { UserDefaults.standard.object(forKey: key) as? T ?? defaultValue }
        set { UserDefaults.standard.set(newValue, forKey: key) }
    }
    
    init(key: String, defaultValue: T) {
        self.key = key
        self.defaultValue = defaultValue
    }
}


要强制设计,您需要更改所有应用程序窗口的样式。

我们在应用程序中实现主题切换。


extension Theme {
    
    @available(iOS 13.0, *)
    var userInterfaceStyle: UIUserInterfaceStyle {
        switch self {
        case .light: return .light
        case .dark: return .dark
        }
    }
    
    func setActive() {
        //   
        save()
        
        guard #available(iOS 13.0, *) else { return }
        
        //       
        UIApplication.shared.windows
            .forEach { $0.overrideUserInterfaceStyle = userInterfaceStyle }
    }
}

在显示窗口之前,还需要将窗口样式更改为当前主题。

extension UIWindow {
    
    //     
    //     
    func initTheme() {
        guard #available(iOS 13.0, *) else { return }
        
        overrideUserInterfaceStyle = Theme.current.userInterfaceStyle
    }
}

选择浅色或深色主题的屏幕截图
图片 图片

将开关添加到系统主题


将系统主题添加到枚举主题。
enum Theme: Int, CaseIterable {
    case system = 0
    case light
    case dark
}

在强行安装浅色或深色主题之后,无法确定系统中包含哪种设计。为了识别系统设计,我们在应用程序中添加了一个窗口,在该窗口中我们不会强制进行设计更改。当应用程序安装了系统主题并且用户在iOS中更改设计时,也有必要实施设计更改。

final class ThemeWindow: UIWindow {
    
    override public func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {

        //         iOS,     .
        // :      .
        if Theme.current == .system {
            Theme.system.setActive()
        }
    }
}

let themeWindow = ThemeWindow()

class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        ...
        //    ,    
        //       
        themeWindow.makeKey()
        ...
        return true
    }
}

extension Theme {
    
    @available(iOS 13.0, *)
    var userInterfaceStyle: UIUserInterfaceStyle {
        switch self {
        case .light: return .light
        case .dark: return .dark
        case .system: return themeWindow.traitCollection.userInterfaceStyle
        }
    }
    
    func setActive() {
        //   
        save()
        
        guard #available(iOS 13.0, *) else { return }
        
        //       
        //        
        UIApplication.shared.windows
            .filter { $0 != themeWindow } 
            .forEach { $0.overrideUserInterfaceStyle = userInterfaceStyle }
    }
}

选择系统,浅色或深色主题的屏幕截图
图片 图片

结果


支持深色设计以及系统,浅色和深色主题之间的切换。
屏幕视频


链接到整个项目

All Articles