问题
I find the behavior of the new iOS 13 UIImage property withTintColor(_:renderingMode:)
incomprehensible. What is it for, and how does it relate to the tint color of the context in which the image appears?
For example:
let im = UIImage(systemName:"circle.fill")?.withTintColor(.red)
let iv = UIImageView(image:im)
iv.frame.origin = CGPoint(x: 100, y: 400)
self.view.addSubview(iv)
I said .red
. But it's blue:
Evidently it's blue because it takes its color from the tint color of the surrounding context. But then what's the point of giving the image itself a tint color?
But it gets even weirder. I'll draw my own image and give it a tint color:
let sz = CGSize(width: 20, height: 20)
let im = UIGraphicsImageRenderer(size:sz).image { ctx in
ctx.cgContext.fillEllipse(in:CGRect(origin:.zero, size:sz))
}.withTintColor(.red)
let iv = UIImageView(image:im)
iv.frame.origin = CGPoint(x: 100, y: 400)
self.view.addSubview(iv)
I said .red
and it's red:
What accounts for the inconsistency?
回答1:
withTintColor
is probably intended primarily for use only with symbol images, which are always treated as templates and have no color of their own. However, it is also very nice to be able to treat an ordinary image as a template and give it a color.
Let's say you're drawing into a custom UIView's draw(_:)
method, or drawing in a UIImageView graphics context. There has always been a problem with template views; you have no access here to their template behavior, so there is no way to tint them. withTintColor
solves that problem.
There is no doubt, however, that the behavior of these methods is profoundly weird when you use them in any other way:
As soon as you say
withTintColor
, the resulting image is treated as a template image, even if you say.alwaysOriginal
. So your rendering mode is now being ignored!Moreover, in contexts where there is already a
tintColor
, there can now be two competing tint colors: that of the context (the surrounding view or the inheritedtintColor
) and that of the image when you saywithTintColor
. And if this is a template image — a symbol image, or an.alwaysTemplate
image, or an image in a template context like a button — then the context'stintColor
wins, and the color that you specifically applied by sayingwithTintColor
is ignored!!
For example, this results in a blue symbol image (because the default image view tintColor
is blue) even though you specifically set the symbol image's tint color to red:
let im = UIImage(systemName:"circle.fill")?.withTintColor(.red)
let iv = UIImageView(image:im)
To get a red symbol image, you have to say this:
let im = UIImage(systemName:"circle.fill")?.withTintColor(.red,
renderingMode: .alwaysOriginal)
So in the first code, the tint color you assign is being ignored (we get blue, not red), but in the second code, the rendering mode you assign is being ignored (it's still a template image, but now it's red as requested). Weird, eh?
(I find it very hard to believe that this is the intended behavior, and I've filed a bug, but so far no response from Apple.)
来源:https://stackoverflow.com/questions/58867627/ios-13-withtintcolor-not-obeying-the-color-i-assign