Как мне легко поддерживать светлый и темный режим с помощью собственного цвета, используемого в моем приложении? - PullRequest
1 голос
/ 07 июня 2019

Допустим, у меня есть собственный цвет в моем приложении:

extension UIColor {
    static var myControlBackground: UIColor {
        return UIColor(red: 0.3, green: 0.4, blue: 0.5, alpha: 1)
    }
}

Я использую его в пользовательском элементе управления (и в других местах) в качестве фона элемента управления:

class MyControl: UIControl {
    override init(frame: CGRect) {
        super.init(frame: frame)

        setup()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)

        setup()
    }

    private func setup() {
        backgroundColor = .myControlBackground
    }

    // Lots of code irrelevant to the question
}

СiOS 13, я хочу, чтобы мой пользовательский элемент управления поддерживал как светлый, так и темный режим.

Одно из решений - переопределить traitCollectionDidChange и посмотреть, изменился ли цвет, а затем обновить свой фон при необходимости.Мне также нужно предоставить как светлый, так и темный цвет.

Поэтому я обновляю свои пользовательские цвета:

extension UIColor {
    static var myControlBackgroundLight: UIColor {
        return UIColor(red: 0.3, green: 0.4, blue: 0.5, alpha: 1)
    }
    static var myControlBackgroundDark: UIColor {
        return UIColor(red: 0.4, green: 0.3, blue: 0.2, alpha: 1)
    }
}

И я обновляю свой контрольный код:

extension MyControl {
    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        super.traitCollectionDidChange(previousTraitCollection)

        if #available(iOS 13.0, *) {
            if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
                backgroundColor = traitCollection.userInterfaceStyle == .dark ?
                   .myControlBackgroundDark : .myControlBackgroundLight
            }
        }
    }
}

Кажется, это работает, но это неуклюже, и везде, где я использую myControlBackground, нужно добавить тот же код.

Есть ли лучшее решение для поддержки моего пользовательского цвета и управления как в светлом, так и в темном режиме?

Ответы [ 2 ]

3 голосов
/ 07 июня 2019

Как оказалось, с новым инициализатором UIColor init(dynamicProvider:) это действительно просто.

Обновить пользовательский цвет:

extension UIColor {
    static var myControlBackground: UIColor {
        if #available(iOS 13.0, *) {
            return UIColor { (traits) -> UIColor in
                // Return one of two colors depending on light or dark mode
                return traits.userInterfaceStyle == .dark ?
                    UIColor(red: 0.5, green: 0.4, blue: 0.3, alpha: 1) :
                    UIColor(red: 0.3, green: 0.4, blue: 0.5, alpha: 1)
            }
        } else {
            // Same old color used for iOS 12 and earlier
            return UIColor(red: 0.3, green: 0.4, blue: 0.5, alpha: 1)
        }
    }
}

Вот и все. Не нужно определять две отдельные статики. Класс управления не требует никаких изменений по сравнению с исходным кодом. Нет необходимости переопределять traitCollectionDidChange или что-либо еще.

Приятно то, что вы можете видеть изменение цвета в переключателе приложений сразу после изменения режима в приложении Настройки. И, конечно, цвет автоматически обновляется, когда вы возвращаетесь в приложение.

Для соответствующей заметки при поддержке светлого и темного режима - используйте максимально возможное количество цветов из UIColor. См. Доступные динамические цвета из Элементы пользовательского интерфейса и Стандартные цвета . И когда вам нужны собственные цвета для приложений, чтобы поддерживать как светлый, так и темный режим, используйте код в этом ответе в качестве примера.


В Objective-C вы можете определить свои собственные динамические цвета с помощью:

UIColor + MyApp.h:

@interface UIColor (MyApp)

@property (class, nonatomic, readonly) UIColor *myControlBackgroundColor;

@end

UIColor + MyApp.m:

+ (UIColor *)myControlBackgroundColor {
    if (@available(iOS 13.0, *)) {
        return [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traits) {
            return traits.userInterfaceStyle == UIUserInterfaceStyleDark ?
                [self colorWithRed:0.5 green:0.4 blue:0.2 alpha:1.0] :
                [self colorWithRed:0.3 green:0.4 blue:0.5 alpha:1.0];
        }];
    } else {
        return [self colorWithRed:0.3 green:0.4 blue:0.5 alpha:1.0];
    }
}
0 голосов
/ 17 июня 2019

Другое решение с iOS 13 заключается в определении пользовательских цветов в вашем каталоге ресурсов с помощью редактора ресурсов Xcode.

Как уже упоминалось в документации , когда вам нужен определенный цвет, создайте его в качестве цветового актива. В вашем активе укажите разные значения цвета для светлых и темных появлений. Вы также можете указать высококонтрастные версии ваших цветов.

enter image description here

Обратите внимание, что вариант Любое появление - это цвет, который отображается в старых системах, не поддерживающих темный режим.

Чтобы загрузить значение цвета из каталога активов, вы можете загрузить цвет по его имени:

// iOS
let aColor = UIColor(named: "customControlColor")

// macOS
let aColor = NSColor(named: NSColor.Name("customControlColor"))

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...