web-dev-qa-db-ja.com

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ベータのバグですか、それとも何か問題がありますか? a GitHub repo があり、この動作を示すコードが含まれています。プロジェクトを実行し、XCodeからダークモードに切り替えて、テキストフィールドに入力を開始します。

10
ov1d1u

簡潔な答え

この場合、動的な色を解決するために使用する特性コレクションを指定する必要があります。

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

または

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

より長い答え

動的cgColorUIColorメソッドを呼び出す場合、動的色の値を解決する必要があります。これは、現在の特性コレクション_UITraitCollection.current_を参照して行われます。

現在のトレイトコレクションは、特定のメソッドのオーバーライドを呼び出すときにUIKitによって設定されます。

  • UIView
    • ドロー()
    • layoutSubviews()
    • traitCollectionDidChange()
    • tintColorDidChange()
  • UIViewController
    • viewWillLayoutSubviews()
    • viewDidLayoutSubviews()
    • traitCollectionDidChange()
  • UIPresentationController
    • containerViewWillLayoutSubviews()
    • containerViewDidLayoutSubviews()
    • traitCollectionDidChange()

ただし、これらのメソッドのオーバーライド以外では、現在のトレイトコレクションが特定の値に設定されているとは限りません。したがって、コードがこれらのメソッドのいずれかでオーバーライドされておらず、動的な色を解決したい場合は、使用する特性コレクションを指定する必要があります。

(それは、任意のビューまたはビューコントローラのuserInterfaceStyle特性をオーバーライドできるためです。そのため、デバイスがライトモードに設定されていても、ビューがダークモードになっている可能性があります。)

UIColorメソッド resolvedColor(with:) を使用してダイナミックカラーを直接解決することで、これを行うことができます。または、UITraitCollectionメソッド performAsCurrent を使用して、色を解決するコードをクロージャー内に配置します。上記の短い答えは両方の方法を示しています。

コードをこれらのメソッドの1つに移動することもできます。この場合、layoutSubviews()に入れることができると思います。これを行うと、明るい/暗いスタイルが変更されたときに自動的に呼び出されるため、他に何もする必要はありません。

参照

WWDC 2019、iOSでのダークモードの実装

19:00から私は動的色がどのように解決されるかについて話し、23:30に、あなたがそうしているように、CALayerの境界線色を動的色に設定する方法の例を示しました。

34
Kurt Revis