У меня есть собственный подкласс 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 или я что-то не так делаю? Есть репозиторий GitHub с кодом, демонстрирующим такое поведение. Запустите проект, переключитесь в темный режим из XCode, затем начните вводить что-то в текстовое поле.
Да, он делает то же самое.
В этой ситуации вам нужно указать, какую коллекцию признаков использовать для разрешения динамического цвета.
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, когда он вызывает ваши переопределения определенных методов, а именно:
Однако, помимо переопределений этих методов, текущая коллекция трейтов не обязательно имеет какое-либо конкретное значение. Итак, если ваш код не переопределяет один из этих методов, и вы хотите разрешить динамический цвет, вы должны сообщить нам, какую коллекцию свойств использовать.
(Это потому, что можно переопределить признак userInterfaceStyle
любого представления или контроллера представления, поэтому, даже если устройство может быть установлено в светлом режиме, у вас может быть представление в темном режиме.)
Вы можете сделать это, напрямую разрешив динамический цвет, используя метод UIColor resolvedColor(with:)
. Или используйте метод performAsCurrent
UITraitCollection и поместите свой код, который разрешает цвет внутри замыкания. Краткий ответ выше показывает оба пути.
Вы также можете переместить свой код в один из этих методов. В этом случае, я думаю, вы могли бы поставить его в layoutSubviews()
. Если вы это сделаете, он будет автоматически вызываться при изменении светлого/темного стиля, поэтому вам больше ничего не нужно делать.
WWDC 2019, Реализация темного режима в iOS
Начиная с 19:00 я говорил о том, как разрешаются динамические цвета, а в 23:30 я представил пример того, как установить динамический цвет границы CALayer
, как вы делаете.
Я отмечаю этот ответ как принятый, так как использование предложенного кода работает, даже когда я перехожу в темный режим с помощью кнопки Environment Overrides в Xcode. Спасибо, что разъяснили, как работает динамический UIColor
.
У меня проблема, аналогичная OP, когда я устанавливаю именованный цвет (созданный в .xassets с цветами, установленными на любой и темный внешний вид) для границы некоторых кнопок, он работает непоследовательно, некоторые кнопки отображаются со светлым цветом, а некоторые с темным цвет. Другая проблема, связанная с layer.borderColor и темным режимом, заключается в том, что когда я переключаюсь со светлого на темный режим (и наоборот) в настройках iOS, он обновляет только цвет границы кнопок (даже когда он отображает правильный внешний вид цвета). ), если я перерисую кнопки (воткну vc и снова нажму). Наверное баг? (проверено в xcode 11 b6)
Кстати, непоследовательное поведение, описанное выше, происходит в iOS 12 (что странно, потому что некоторые границы отображаются с темным внешним видом, хотя в iOS 12 нет поддержки темного режима), и необходимость перерисовки для получения правильного цвета после изменения режимов происходит в iOS 13b
@ LeeAndrew, ты нашел исправление?
@airowe Я тоже. Это сработало для меня: stackoverflow.com/questions/58312095/…
@rs7 Понял, спасибо! Это сработало для меня. Вот прямая ссылка на ответ: stackoverflow.com/a/58312205/1496693
@ Курт Ревис, есть ли аналогичный ответ для macOS? Я не мог найти его.
У меня были проблемы с некоторыми UIView
подклассами, которые не учитывали варианты темного режима моих цветов XCAsset, но: UIColor(named: "testColor")?.resolvedColor(with: self.traitCollection)
это исправлено. Спасибо!
Это не работает. UIColor.text всегда возвращает черный цвет в темном режиме, что делает его нечитаемым.
Вы можете добавить невидимое подпредставление в ваше представление, и оно будет отслеживать события 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?()
}
}
}
вы пытались запустить это на устройстве и сделать это?