I have a function that accepts a UIColor.
func getColor(_ background: UIColor) -> UIColor {
switch background {
case .white, .systemBrown:
return .black
case .darkGray:
return .lightGray
case .black:
return .white
default:
return .label
}
}
and I have UIButton with background color .systemBrown
let brownButton: UIButton = {
let btn = UIButton()
btn.translatesAutoresizingMaskIntoConstraints = false
btn.backgroundColor = .systemBrown
btn.layer.borderWidth = 1.0
btn.layer.borderColor = UIColor.brown.cgColor
return btn
}()
When i call the function like this:
getColor(brownButton.backgroundColor!)
It returns .label (default case). But when i use:
getColor(.systemBrown)
I get the expected result
CodePudding user response:
The "system" colors are dynamic based on the trait collection of what they are applied to.
Printing the various colors gives you an idea of the differences:
let color = view.backgroundColor!
print("Background: \(color)")
print("SystemBrown: \(UIColor.systemBrown)")
The output is:
Background: <UIDynamicModifiedColor: 0x60000394d6e0; contrast = normal, baseColor = <UIDynamicCatalogSystemColor: 0x600002277000; name = systemBrownColor>>
SystemBrown: <UIDynamicCatalogSystemColor: 0x600002277000; name = systemBrownColor>
This indicates that applying the systemBrown
color to the view changed the color's properties a bit. This means it is no longer equal to a "plain" systemBrown
color any more.
One solution is to resolve all relevant colors to the appropriate trait collection.
Update getColors
by resolving any dynamic colors used in case
statements:
func getColor(_ background: UIColor, traits: UITraitCollection) -> UIColor {
switch background {
case .white, .systemBrown.resolvedColor(with: traits):
return .black
case .darkGray:
return .lightGray
case .black:
return .white
default:
return .label
}
}
Then update your call to getColors
:
getColor(color.resolvedColor(with: view.traitCollection), traits: view.traitCollection)
You need to resolve the passed background color as well as pass the view's traitCollection
to getColors
.
If you always work on a view's backgroundColor
you could change getColors
to take just a UIView
parameter and resolve the colors inside that function as needed.
CodePudding user response:
It might be that the system is doing something to the background color like applying a tint to it.
I would suggest logging the RGB and alpha values of UIColor.systemBrown and of your brownButton's backgroundColor. You might find that they are slightly different. In that case you might need to write a "color close to another color" comparison. (Say the R, G, and B components are within 0.02 of each other? Or within 5 for integer values from 0-255. I just pulled those ranges out of thin air, but they are probably a good starting point.)
Something like this:
extension UIColor {
func isSimilarToColor(_ otherColor: UIColor) -> Bool {
var myRed: CGFloat = 0
var myGreen: CGFloat = 0
var myBlue: CGFloat = 0
var myAlpha: CGFloat = 0
var otherRed: CGFloat = 0
var otherGreen: CGFloat = 0
var otherBlue: CGFloat = 0
var otherAlpha: CGFloat = 0
self.getRed(&myRed, green: &myGreen, blue: &myBlue, alpha: &myAlpha)
otherColor.getRed(&otherRed, green: &otherGreen, blue: &otherBlue, alpha: &otherAlpha)
let slop: CGFloat = 0.02
return
myAlpha == 1.0 && otherAlpha == 1.0 &&
abs(myRed-otherRed) < slop &&
abs(myGreen-otherGreen) < slop &&
abs(myBlue-otherBlue) < slop
}
}