UIColor возвращает неправильные значения для цветов темного режима
У меня есть обычай UITextField
подкласс, который меняет цвет границы при наборе чего-либо в нем. Я слушаю изменения по телефону
self.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
а затем, в textFieldDidChange(_:)
Я делаю:
self.layer.borderColor = UIColor(named: "testColor")?.cgColor
где testColor
это цвет, определенный в Assets.xcassets с вариантами для светлого и темного режима. Проблема в том, что UIColor(named: "testColor")?.cgColor
кажется, всегда возвращает цвет для режима освещения.
Это ошибка в iOS 13 beta или я делаю что-то не так? Есть репозиторий GitHub с кодом, который демонстрирует такое поведение. Запустите проект, переключитесь в темный режим из XCode, затем начните вводить что-то в текстовое поле.
3 ответа
Краткий ответ
В этой ситуации вам нужно указать, какую коллекцию признаков использовать для разрешения динамического цвета.
self.traitCollection.performAsCurrent {
self.layer.borderColor = UIColor(named: "testColor")?.cgColor
}
или же
self.layer.borderColor = UIColor(named: "testColor")?.resolvedColor(with: self.traitCollection).cgColor
Более длинный ответ
Когда вы звоните cgColor
метод на динамическом UIColor
, он должен разрешить значение динамического цвета. Это делается путем обращения к текущей коллекции признаков, UITraitCollection.current
,
Текущая коллекция признаков устанавливается UIKit, когда он вызывает ваши переопределения определенных методов, а именно:
- UIView
- рисовать()
- layoutSubviews ()
- traitCollectionDidChange ()
- tintColorDidChange ()
- UIViewController
- viewWillLayoutSubviews ()
- viewDidLayoutSubviews ()
- traitCollectionDidChange ()
- UIPresentationController
- containerViewWillLayoutSubviews ()
- containerViewDidLayoutSubviews ()
- traitCollectionDidChange ()
Однако вне переопределений этих методов текущая коллекция признаков не обязательно должна иметь какое-либо конкретное значение. Итак, если ваш код не переопределяет один из этих методов, и вы хотите разрешить динамический цвет, вы обязаны сообщить нам, какую коллекцию признаков использовать.
(Это потому, что можно переопределить userInterfaceStyle
черта любого вида или контроллера вида, поэтому, даже если устройство может быть установлено в светлый режим, у вас может быть вид, который находится в темном режиме.)
Вы можете сделать это, непосредственно разрешив динамический цвет, используя метод UIColor resolvedColor(with:)
, Или используйте метод UITraitCollection performAsCurrent
и поместите ваш код, который разрешает цвет внутри замыкания. Краткий ответ выше показывает оба пути.
Вы также можете переместить свой код в один из этих методов. В этом случае, я думаю, вы могли бы положить его в layoutSubviews()
, Если вы сделаете это, он будет автоматически вызываться при изменении стиля свет / темнота, так что вам больше не нужно будет ничего делать.
Ссылка
WWDC 2019, Реализация темного режима в iOS
Начиная с 19:00, я говорил о том, как разрешаются динамические цвета, а в 23:30 я представил пример того, как установить CALayer
Цвет границы в динамический цвет, как вы делаете.
Вы можете добавить невидимое подпредставление к вашему просмотру, и оно будет отслеживать события traitCollectionDidChange.
пример:
import UIKit
extension UIButton {
func secondaryStyle() {
backgroundColor = .clear
layer.cornerRadius = 8
layer.borderWidth = 1
layer.borderColor = UIColor(named: "borderColor")?.cgColor
moon.updateStyle = { [weak self] in
self?.secondaryStyle()
}
}
}
extension UIView {
var moon: Moon {
(viewWithTag(Moon.tag) as? Moon) ?? .make(on: self)
}
final class Moon: UIView {
static var tag: Int = .max - 1
var updateStyle: (() -> Void)?
static func make(on view: UIView) -> Moon {
let moon = Moon()
moon.tag = Moon.tag
view.addSubview(moon)
return moon
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
guard previousTraitCollection?.userInterfaceStyle != traitCollection.userInterfaceStyle else { return }
triggerUpdateStyleEvent()
}
func triggerUpdateStyleEvent() {
updateStyle?()
}
}
}
Я собираюсь опубликовать это как ответ, так как я только что нашел, в чем проблема. Кажется, это ошибка, если я активирую Dark Appearance из Simulator -> Settings -> Developer, UITextField имеет ожидаемый цвет. Проблема появляется, только если я установил стиль интерфейса темным от кнопки Переопределения среды в XCode.