133

I have my own subclass of UIButton. I add UIImageView on it and add an image. I would like to paint it over the image with a tint color but it doesn't work.

So far I have:

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {

        self.backgroundColor = [UIColor clearColor];
        self.clipsToBounds = YES;

        self.circleView = [[UIView alloc]init];
        self.circleView.backgroundColor = [UIColor whiteColor];
        self.circleView.layer.borderColor = [[Color getGraySeparatorColor]CGColor];
        self.circleView.layer.borderWidth = 1;
        self.circleView.userInteractionEnabled = NO;
        self.circleView.translatesAutoresizingMaskIntoConstraints = NO;
        [self addSubview:self.circleView];

        self.iconView = [[UIImageView alloc]init];
        [self.iconView setContentMode:UIViewContentModeScaleAspectFit];
        UIImage * image = [UIImage imageNamed:@"more"];
        [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
        self.iconView.image = image;
        self.iconView.translatesAutoresizingMaskIntoConstraints = NO;
        [self.circleView addSubview:self.iconView];
        ...

and on selection :

- (void) setSelected:(BOOL)selected
{
    if (selected) {
        [self.iconView setTintColor:[UIColor redColor]];
        [self.circleView setTintColor:[UIColor redColor]];
    }
    else{
        [self.iconView setTintColor:[UIColor blueColor]];
        [self.circleView setTintColor:[UIColor blueColor]];
    }  
}

What did I do wrong? (The color of the image always stays the same as it was originally.)

shim
  • 9,289
  • 12
  • 69
  • 108
Marko Zadravec
  • 8,298
  • 10
  • 55
  • 97

9 Answers9

249

Instead of this code:

[image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];

you should have:

image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];

Use this in Swift 4.1

image = UIImage(named: "name")!.withRenderingMode(.alwaysTemplate)
eharo2
  • 2,553
  • 1
  • 29
  • 39
Marko Zadravec
  • 8,298
  • 10
  • 55
  • 97
  • 9
    Not a stupid mistake, but a very important detail. Thanks for posting this. You just saved me lots of time. (corrected typo) – Alex Zavatone Aug 20 '15 at 18:37
  • 49
    You can select image in assets and select in right panel default rendering mode – Nikolay Shubenkov Oct 22 '15 at 13:48
  • Excellent! But how do you revert back to the original un-tinted image? – Marsman Jul 10 '16 at 20:49
  • If you want to get un-tinted image you could : store tinted one in different variable : UIImage image2 = [image imageWithR....], or you can load image from file again : image = [UIImage imageNamed:@"more"]; – Marko Zadravec Jul 11 '16 at 04:45
  • I found strange problem with UIImageRenderingModeAlwaysTemplate. If you turn on 'Bold Text' in iOS Setting > Display & Brightness, imageWithRenderingMode: UIImageRenderingModeAlwaysTemplate causes memory leak (image data is never deallocated). It is probably system bug and it may happen also with some other iOS settings. I recommend using "func withTintColor(_ color: UIColor) -> UIImage" added in iOS 13 instead of .tintColor. – Slyv Jun 01 '21 at 09:11
  • EXCELLENT!! you make me happy. appreciate for save my time. – Kang Developer Apr 01 '22 at 03:20
104

You can also just set this on your asset. Make sure your image contains all white pixels + transparent. enter image description here

StackUnderflow
  • 2,403
  • 2
  • 21
  • 28
  • 6
    I did all of this, but for some reason the tintColor does not work for me. Any idea what else I could try? – Banana Dec 15 '16 at 14:37
  • 1
    What kind of image format are you using? And is the image all white + alpha? – StackUnderflow Dec 24 '16 at 00:01
  • 4
    Weirdly on my first couple of runs only 2/3 images picked up the tint color. After clean and build all of the images picked up the tint. – MathewS Jan 18 '17 at 21:29
  • Maybe you could report that to Apple? – StackUnderflow Jan 20 '17 at 15:05
  • I think it's just old cache. – StackUnderflow Feb 17 '17 at 10:36
  • 13
    @Banana, this is a known issue of the images not using the tint color. I had reported it to Apple a while back and they marked it as a duplicate so they definitely know about it. The workaround is to not set your UIImageView to an image on the Storyboard. So just have a blank UIImageView and then set it in the viewDidLoad (or somewhere else) and you will then see the tintColor on the image. – Mark Moeykens May 03 '17 at 16:36
  • @Banana I had this bug too and even by code it was not working. I solved this problem like this: 1. Unset UIImageView's image. 2. Run your app with the empty UIimageview. 3. Set your image to the UIImageView. Make sure UIImageView's tintColor is set to the color of your choice in "User Defined Runtime Attributes" and in "Attributes Inspector" too. Also make sure your image is always template. 4. Run again your app and it should work. – Nakwenda May 18 '19 at 04:49
  • 1
    @MarkMoeykens More than 4 years later and your solution still works, thank you. – Ricardo Yubal Dec 28 '21 at 06:54
41

(Can't edit @Zhaolong Zhong post)

In swift 3.0, you can do:

let image = UIImage(named: "your_image_name")!.withRenderingMode(.alwaysTemplate)

yourImageView.image = image

yourImageView.tintColor = UIColor.blue
odemolliens
  • 2,581
  • 2
  • 32
  • 34
22

Swift version: 5.2

let tintableImage = UIImage(named: "myImage")?.withRenderingMode(.alwaysTemplate)
imageView.image = tintableImage
imageView.tintColor = UIColor.red

Objective C

self.imgView.image = [self.imgView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[self.imgView setTintColor:[UIColor darkGrayColor]];

Or

You can also just set this on your asset.

enter image description here

Nischal Hada
  • 3,230
  • 3
  • 27
  • 57
19

In swift 2.0+, you can do:

let image = UIImage(named: "your_image_name")!.imageWithRenderingMode(.AlwaysTemplate)

yourImageView.image = image

yourImageView.tintColor = UIColor.blueColor()
Zhaolong Zhong
  • 300
  • 3
  • 6
8

One step further. This is a drop-in subclass of UIImageView. (Not exact solution for original question.) Use in Interface Builder by setting class name to TintedImageView. Updates in real-time inside the designer as tint color changes.

(Swift 3.1, Xcode 8.3)

import UIKit

@IBDesignable class TintedImageView: UIImageView {
    override func prepareForInterfaceBuilder() {
        self.configure()
    }

    override func awakeFromNib() {
        super.awakeFromNib()

        self.configure()
    }

    @IBInspectable override var tintColor: UIColor! {
        didSet {
            self.configure()
        }
    }

    private func configure() {
        self.image = self.image?.withRenderingMode(UIImageRenderingMode.alwaysTemplate)
    }
}
Daniel
  • 8,794
  • 4
  • 48
  • 71
  • 4
    not working, but it modify func configure to : self.image = self.image?.withRenderingMode(UIImageRenderingMode.alwaysTemplate) let color = super.tintColor super.tintColor = UIColor.clear super.tintColor = color – lolo_house May 04 '17 at 10:21
5

Make the imageView

    let imageView = UIImageView(frame: frame!)
    imageView.contentMode = .ScaleAspectFit
    imageView.tintColor = tintColor

Make the image

    let mainBundle = NSBundle.mainBundle()
    var image = UIImage(named: filename!, inBundle: mainBundle, compatibleWithTraitCollection: nil)
    image = image?.imageWithRenderingMode(.AlwaysTemplate)

Wire them together

    imageView?.image = image

Display it

view.addSubview(imageView)
Gary Davies
  • 920
  • 15
  • 12
1

all said is correct. my contribution If You cannot / dont want to apply to every UiImageView, OR for efficiency You need to render ONCE (or example for cells of tableviews)

func tint(with color: UIColor) -> UIImage {
        var image = withRenderingMode(.alwaysTemplate)
        UIGraphicsBeginImageContextWithOptions(size, false, scale)
        color.set()

        image.draw(in: CGRect(origin: .zero, size: size))
        image = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        return image
    }

And set to all UI elements this UIImage.

ingconti
  • 10,876
  • 3
  • 61
  • 48
1

@odemolliens answer should just work.

But if you are still having issues, make sure that the tint color you are applying to the UIImageView is different from the one defined in the Interface Builder.

rockdaswift
  • 9,613
  • 5
  • 40
  • 46