我有一个自定义的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中的错误,还是我做错了什么?带有a GitHub repo的代码可以展示这种行为。运行项目,从XCode切换到暗模式,然后开始在文本字段中输入内容。
答案 0 :(得分:2)
在这种情况下,您需要指定使用哪个特征集合来解析动态颜色。
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:)
直接解析动态颜色来实现。或使用UITraitCollection方法performAsCurrent
,然后将用于解析颜色的代码放入闭包中。上面的简短答案显示了两种方式。
您还可以将代码移入这些方法之一。在这种情况下,我认为您可以将其放在layoutSubviews()
中。如果这样做,则当明暗样式更改时,它将自动被调用,因此您无需执行其他任何操作。
WWDC 2019, Implementing Dark Mode in iOS
从19:00开始,我谈到了动态色彩的分辨方式,在23:30,我举了一个示例,说明如何将CALayer
的边框颜色设置为动态颜色,就像您做。
答案 1 :(得分:0)
由于我刚刚发现问题所在,因此我将其发布为答复。如果我从Simulator-> Settings-> Developer激活Dark Appearance,这似乎是一个错误,UITextField具有预期的颜色。仅当我从Xcode中的“环境覆盖”按钮将界面样式设置为深色时,才会出现该问题。
答案 2 :(得分:0)
您可以在视图上添加不可见的子视图,它会跟踪 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?()
}
}
}