web-dev-qa-db-fra.com

UIColor renvoie des valeurs incorrectes pour les couleurs en mode sombre

J'ai une sous-classe UITextField personnalisée qui change sa couleur de bordure lors de la saisie de quelque chose. J'écoute les changements en appelant

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

et puis, dans textFieldDidChange(_:) je fais:

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

testColor est une couleur définie dans Assets.xcassets avec des variantes pour le mode clair et sombre. Le problème est que UIColor(named: "testColor")?.cgColor semble toujours renvoyer la couleur du mode lumière.

Est-ce un bug dans iOS 13 beta ou je fais quelque chose de mal? Il y a n dépôt GitHub avec le code qui présente ce comportement. Exécutez le projet, passez en mode sombre à partir de XCode, puis commencez à taper quelque chose dans le champ de texte.

10
ov1d1u

Réponse courte

Dans cette situation, vous devez spécifier la collection de traits à utiliser pour résoudre la couleur dynamique.

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

ou

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

Réponse plus longue

Lorsque vous appelez la méthode cgColor sur un UIColor dynamique, elle doit résoudre la valeur de la couleur dynamique. Cela se fait en se référant à la collection de traits actuelle, UITraitCollection.current.

La collection de traits actuelle est définie par UIKit lorsqu'il appelle vos remplacements de certaines méthodes, notamment:

  • UIView
    • dessiner()
    • layoutSubviews ()
    • traitCollectionDidChange ()
    • tintColorDidChange ()
  • UIViewController
    • viewWillLayoutSubviews ()
    • viewDidLayoutSubviews ()
    • traitCollectionDidChange ()
  • UIPresentationController
    • containerViewWillLayoutSubviews ()
    • containerViewDidLayoutSubviews ()
    • traitCollectionDidChange ()

Cependant, en dehors des remplacements de ces méthodes, la collection de caractères actuelle n'est pas nécessairement définie sur une valeur particulière. Donc, si votre code ne remplace pas l'une de ces méthodes et que vous souhaitez résoudre une couleur dynamique, il est de votre responsabilité de nous dire quelle collection de traits utiliser.

(C'est parce qu'il est possible de remplacer le trait userInterfaceStyle de n'importe quelle vue ou contrôleur de vue, donc même si le périphérique peut être réglé en mode clair, vous pouvez avoir une vue qui est en mode sombre.)

Vous pouvez le faire en résolvant directement la couleur dynamique, en utilisant la méthode UIColor resolvedColor(with:) . Ou utilisez la méthode UITraitCollection performAsCurrent , et mettez votre code qui résout la couleur à l'intérieur de la fermeture. La réponse courte ci-dessus montre les deux façons.

Vous pouvez également déplacer votre code dans l'une de ces méthodes. Dans ce cas, je pense que vous pouvez le mettre dans layoutSubviews(). Si vous faites cela, il sera automatiquement appelé lorsque le style clair/foncé change, vous n'aurez donc pas besoin de faire autre chose.

Référence

WWDC 2019, implémentation du mode sombre dans iOS

À partir de 19h00, j'ai parlé de la façon dont les couleurs dynamiques sont résolues et à 23h30, j'ai présenté un exemple de la façon de définir la couleur de bordure d'un CALayer sur une couleur dynamique, tout comme vous le faites.

34
Kurt Revis