Как создать инициализатор с dynamicProvider для темного режима

Работая над поддержкой темного режима, я смог получить динамические цвета, которые меняются при смене тем, используя этот шаблон:

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
    }
}()

Я пытаюсь упростить создание UIColor между iOS 12 и 13 с поддержкой темного режима. Я придумал простое 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 не получает обновленное значение, поэтому цвета не меняются. Вот как я объявляю Theme с инициализатором init(dynamicProvider:), но похоже, что 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
        }
    }
}

Что я здесь делаю не так? Я думаю, что именно так и должен работать этот инициализатор, но я не смог найти других примеров этого в Интернете ...


person manolosavi    schedule 14.10.2019    source источник


Ответы (1)


Ладно, после долгой возни я все еще не понимаю, почему исходная реализация не работает, но я нашел другой способ заставить ее работать! Итак, если вы пытаетесь упростить свою реализацию для поддержки 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
        }
    }
}
person manolosavi    schedule 15.10.2019