iOS 13 `withTintColor` not obeying the color I assign

风流意气都作罢 提交于 2020-11-28 07:56:20

问题


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 inherited tintColor) and that of the image when you say withTintColor. 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's tintColor wins, and the color that you specifically applied by saying withTintColor 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!