UIImageView doesn't always tint template image

2019-02-02 02:40发布

In the case below, there are two UIImageViews with the same settings and the same template image... But one tints the image, and one does not

I duplicated working UIImageView and placed it instead of the other and it worked. This happened to me multiple times and this solution always worked, but I still wonder what could I have done wrong? Can it be an Xcode bug? Did something similar happen to you? I have Xcode 8.1.

Xcode screenshot

Xcode screenshot

8条回答
劫难
2楼-- · 2019-02-02 03:18

The problem stems from the value for tint having no null state (within the Storyboard/Interface Builder UI). In order for Xcode to decide whether a tint should be applied to a UIImageView there appears to be an additional test. In Xcode this is apparently done by evaluating the constraints applied to UIImageView. As far as I know this test is undocumented.

If you only have a "Spacing to nearest neighbor" constraint on two (or one) sides of your UIImageView then the tint is not applied regardless of the value set for UIImage.renderingMode.

If you have a "Spacing to nearest neighbor" constraint on three (or all) sides of your UIImageView then the tint is applied if the UIImage.renderingMode is set to .alwaysTemplate.

In a purely Storyboard/Interface Builder approach you set the UIImage.renderingMode of an image by adding it to an Asset Catalogue and then changing the "Render As" property of the Image Set to "Template Image".

查看更多
成全新的幸福
3楼-- · 2019-02-02 03:20

use this extension to set UIImageView tintColor from interface builder.

extension UIImageView {
    @IBInspectable var imageColor: UIColor! {
        set {
            super.tintColor = newValue
        }
        get {
            return super.tintColor
        }
    }
} 
查看更多
Rolldiameter
4楼-- · 2019-02-02 03:26

By removing my existing UIImageView and adding a new one my problem was gone. Apparently, the situation is that you should add the UIImageView AFTER adding the images to the Assets folder.

查看更多
霸刀☆藐视天下
5楼-- · 2019-02-02 03:30

Best solution I found that doesn't require a subclass or another IBInspectable attribute:

import UIKit

extension UIImageView {
    override open func awakeFromNib() {
        super.awakeFromNib()
        tintColorDidChange()
    }
}
查看更多
虎瘦雄心在
6楼-- · 2019-02-02 03:31

I think there is a bug in UIImageView. If you set a tint color in the storyboard, it doesn't apply that tint even when the asset is set up to render as template.

The workaround is to apply the tint color to the UIImageView's parent view in the storyboard.

Or, set the tintColor to nil and then back again in code by binding the UIImageView to an outlet.

查看更多
我只想做你的唯一
7楼-- · 2019-02-02 03:31

Runtime attribute trick did not work for me. I made this class just for fixing this kind of stuff. You'll just set to this class all the problematic image views.

final class TintedImageView: UIImageView {

    // WORKAROUND: Template images are not tinted for image views added using the Inteface Builder.
    override func layoutSubviews() {
        super.layoutSubviews()
        let preferredTintColor = tintColor
        tintColor = nil
        tintColor = preferredTintColor
    }

}
查看更多
登录 后发表回答