UIImageView doesn't always tint template image
IosObjective CXcodeUiimageviewIos Problem Overview
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.
Ios Solutions
Solution 1 - Ios
Easy fix solution:
Just add a new runtime attribute which will set the tintColor of the UIImageView to the specified color and ensure the image is tinted.
You will still need to set your image to be rendered as a template image in your Images.xcassets file.
This way you dont need any additional outlets, extensions or lines of code.
Also take note: It will not apply the tintColor in the user defined attribute if the tintColor on the view is the same color, they must be different.
Solution 2 - Ios
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()
}
}
Solution 3 - Ios
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".
Solution 4 - Ios
Try setting tintColor
programmatically; it fixed the issue for me.
Solution 5 - Ios
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.
Solution 6 - Ios
use this extension to set UIImageView tintColor from interface builder.
extension UIImageView {
@IBInspectable var imageColor: UIColor! {
set {
tintColor = newValue
}
get {
tintColor
}
}
}
Solution 7 - Ios
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 when set using the Interface Builder.
override func layoutSubviews() {
super.layoutSubviews()
let preferredTintColor = tintColor
tintColor = nil
tintColor = preferredTintColor
}
}
Solution 8 - Ios
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.
Solution 9 - Ios
Keep default tint colour in storyboard
and add User defined runtime attribute with your chosen colour
The storyboard will show the image with default tint but when you run, it will show your selected colour.
Solution 10 - Ios
Maybe it helps as I was banging my head for an hour until I realised something that I still quite don't understand.
I had my view in my .nib file and all the outlets except one (the UIImageView) had a non default tint colour. I tried all the suggested answer but the issue was solved by selecting a default tint colour for changing it after programatically.
Might it a bug?
Solution 11 - Ios
I had this issue with XCode 10.3. It's an XCode bug which seems to be related to adding an image to storyboard before adding it to assets.
What helped me is changing tint color to some random color then changing it back to default.
As a result XCode added <color key="tintColor" red="0.0" green="0.47843137250000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
to storyboard XML which was missing before. Although it's added as colorSpace="custom"
the XCode builder shows it as default
.
Solution 12 - Ios
As @richardjsimkins mentioned, this does seem to at least in some cases have to do with constraints. In my case I wanted to add an image to the center of the launch screen, since in this case I am not able to set the tintColor programmatically. I had to find a pure Storyboard solution.
I found that the tintColor was not set when centering the image view with constraints, i.e. center horizontally/vertically in safe area, which corresponds to it having no "Spacing to nearest neighbor" constraints.
Instead I added a stack view with constraints to safe area leading/trailing/top/bottom and then embedded the image view in the safe area with alignment center, distribution fill. This resolves to the same positioning as directly centering the imageView in the safe area and this made the tintColor take effect.
I do not like having to resolve to using a stack view to force the tintColor to work, but I think it's a small and fairly clean workaround to the bug.
Solution 13 - Ios
iOS UIImageView and tint color and template image
tintColor
has effect only ontemplate image
template image
will change all colors(except colors with alpha 0 - transparent color) to selected color and only Alpha will be taken into account.
It means that result image will be colorized into single color(tint color) with different alphas. That is why you can not colorize some specific parts of your image
Set image as template:
// Programmatic
let imageView = UIImageView()
imageView.image = imageView.image?.withRenderingMode(.alwaysTemplate)
// Xcode
<select image in assets> -> Attributes Inspector -> Render As -> Template Image
https://i.stack.imgur.com/nnoNE.png" height="100" />
Set tint color
imageView.tintColor = .red
> When you add a template image to a button or image view, you also specify a tint color. The view applies the tint color to every pixel that doesn't have an alpha of 0.0, causing the image's shape to adopt that color. To support different appearances, simply change the tint color. For example, you might apply a dark tint color in light environments and a light tint color in dark environments.
official doc - Create Tintable Images Using Template Images
Additional notes
- When you set image as template(and don't set tintColor) - imageview will be colorized into default tint color
- SVG staff
- fill="#RRGGBBAA" doesn't work, you can use fill-opacity="0-1" instead