如何使用 dynamicProvider 为暗模式创建初始化器

How to create an initializer with dynamicProvider for dark mode

致力于支持深色模式,我已经能够使用这种模式让动态颜色随着您更改主题而变化:

static var dynamicColor: UIColor = {
    if #available(iOS 13, *) {
        return UIColor { (traitCollection: UITraitCollection) -> UIColor in
            switch (traitCollection.userInterfaceStyle, traitCollection.accessibilityContrast) {
            case (.dark, .high):
                return .somethingCustom4

            case (.dark, _):
                return .somethingCustom2

            case (_, .high):
                return .somethingCustom3

            default:
                return .somethingCustom1
            }
        }

    } else {
        return .somethingCustom1
    }
}()

我正在尝试通过支持暗模式来简化 iOS 12 和 13 之间 UIColor 的创建。我想出了一个简单的 Theme 枚举来封装上面的所有逻辑,它只暴露了 4 个案例,所以上面的声明简化为:

static var customColor: UIColor = {
    switch UIColor.theme {
    case .light:
        return somethingCustom1

    case .dark:
        return .somethingCustom2

    case .lightHighContrast:
        return somethingCustom3

    case .darkHighContrast:
        return .somethingCustom4
    }
}()

问题是,虽然在简化之前一切都按预期更新,但现在 theme 没有获得更新的值,所以颜色没有改变。这就是我用 init(dynamicProvider:) 初始化程序声明 Theme 的方式,但是当您在 dark/light 模式之间切换时, UITraitCollection.current 似乎没有正确的值:

public enum Theme {
    case light, dark, lightHighContrast, darkHighContrast

    @available(iOSApplicationExtension 13.0, *)
    init(dynamicProvider: @escaping (UITraitCollection) -> Theme) {
        self = dynamicProvider(UITraitCollection.current)
    }
}

public extension UIColor {
    static var theme: Theme {
        if #available(iOS 13, *) {
            return Theme { (traitCollection: UITraitCollection) -> Theme in
                switch (traitCollection.userInterfaceStyle, traitCollection.accessibilityContrast) {
                case (.dark, .high):
                    return .darkHighContrast

                case (.dark, _):
                    return .dark

                case (_, .high):
                    return .lightHighContrast

                default:
                    return .light
                }
            }

        } else {
            return .light
        }
    }
}

我在这里做错了什么?我认为这就是该初始化程序应该如何工作,但我无法在网上找到任何其他示例……

好吧,经过一番折腾,我仍然不确定为什么原来的实现不起作用,但我确实找到了另一种方法让它起作用!因此,如果您试图简化对 iOS 12 和 13 的支持的实现,这就是我最终得到的结果:

public extension UIColor {
    private static func make(dynamicProvider: @escaping (Theme) -> UIColor) -> UIColor {
        guard #available(iOSApplicationExtension 13.0, *) else { return dynamicProvider(.light) }
        return UIColor { (traitCollection) -> UIColor in
            return dynamicProvider(Theme(traitCollection))
        }
    }

    static var customColor: UIColor {
        return .make { (theme) -> UIColor in
            switch theme {
            case .light:
                return .somethingCustom1

            case .dark:
                return .somethingCustom2

            case .lightHighContrast:
                return .somethingCustom3

            case .darkHighContrast:
                return .somethingCustom4
            }
        }
    }
}

public enum Theme {
    case light, dark, lightHighContrast, darkHighContrast

    @available(iOSApplicationExtension 13.0, *)
    init(_ traitCollection: UITraitCollection) {
        switch (traitCollection.userInterfaceStyle, traitCollection.accessibilityContrast) {
        case (.dark, .high):
            self = .darkHighContrast

        case (.dark, _):
            self = .dark

        case (_, .high):
            self = .lightHighContrast

        default:
            self = .light
        }
    }
}