首页 > 解决方案 > UIColor 为深色模式颜色返回错误值

问题描述

我有一个自定义UITextField子类,在其中输入内容时会更改其边框颜色。我正在通过调用来监听变化

self.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)

然后,textFieldDidChange(_:)我正在做:

self.layer.borderColor = UIColor(named: "testColor")?.cgColor

Assets.xcassets 中定义的颜色在哪里testColor,其中包含明暗模式的变体。问题是它UIColor(named: "testColor")?.cgColor似乎总是返回灯光模式的颜色。

这是 iOS 13 测试版中的错误还是我做错了什么?有一个 GitHub 存储库,其中包含展示此行为的代码。运行项目,从 XCode 切换到暗模式,然后开始在文本字段中输入内容。

标签: iosswiftuitextfieldios13ios-darkmode

解决方案


简短的回答

在这种情况下,您需要指定使用哪个特征集合来解析动态颜色。

self.traitCollection.performAsCurrent {
    self.layer.borderColor = UIColor(named: "testColor")?.cgColor
}

或者

self.layer.borderColor = UIColor(named: "testColor")?.resolvedColor(with: self.traitCollection).cgColor

更长的答案

当您cgColor在 dynamic 上调用该方法时UIColor,它需要解析动态颜色的值。这是通过引用当前特征集合来完成的,UITraitCollection.current.

当前的特征集合是由 UIKit 在调用某些方法的覆盖时设置的,特别是:

  • 界面视图
    • 画()
    • 布局子视图()
    • traitCollectionDidChange()
    • tintColorDidChange()
  • UIViewController
    • viewWillLayoutSubviews()
    • viewDidLayoutSubviews()
    • traitCollectionDidChange()
  • UIPresentationController
    • containerViewWillLayoutSubviews()
    • containerViewDidLayoutSubviews()
    • traitCollectionDidChange()

但是,在这些方法的覆盖之外,当前特征集合不一定设置为任何特定值。因此,如果您的代码没有覆盖这些方法之一,并且您想要解析动态颜色,那么您有责任告诉我们要使用什么特征集合。

(这是因为可以覆盖userInterfaceStyle任何视图或视图控制器的特征,因此即使设备可能设置为亮模式,您也可能拥有处于暗模式的视图。)

您可以通过使用 UIColor 方法直接解析动态颜色来做到这一点resolvedColor(with:)。或者使用 UITraitCollection 方法performAsCurrent,并将解析颜色的代码放在闭包内。上面的简短回答显示了两种方式。

您还可以将您的代码移动到其中一种方法中。在这种情况下,我认为您可以将其放入layoutSubviews(). 如果你这样做,它会在明暗风格改变时自动被调用,所以你不需要做任何其他事情。

参考

WWDC 2019,在 iOS 中实现暗模式

Starting at 19:00 I talked about how dynamic colors get resolved, and at 23:30 I presented an example of how to set a CALayer's border color to a dynamic color, just like you're doing.


推荐阅读