52

I want not to change the backgroundColor of an UIImage, but rather to change the color of the whole image.

But the problem is: I can only change the backgroundColor.

Tamás Sengel
  • 55,884
  • 29
  • 169
  • 223
Studie
  • 799
  • 2
  • 12
  • 20

8 Answers8

130

The accepted answer is correct, but there is a much more easy way for UIImageView:

Obj-C:

UIImage *image = [UIImage imageNamed:@"foo.png"];
theImageView.image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[theImageView setTintColor:[UIColor redColor]];

Swift 2:

let theImageView = UIImageView(image: UIImage(named:"foo")!.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate))
theImageView.tintColor = UIColor.redColor()

Swift 3:

let theImageView = UIImageView(image: UIImage(named:"foo")!.withRenderingMode(.alwaysTemplate))
theImageView.tintColor = UIColor.red
skywinder
  • 21,291
  • 15
  • 93
  • 123
64
UIImage *image = [UIImage imageNamed:@"triangle.png"];

CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClipToMask(context, rect, image.CGImage);
CGContextSetFillColorWithColor(context, [[UIColor redColor] CGColor]);
CGContextFillRect(context, rect);
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

UIImage *flippedImage = [UIImage imageWithCGImage:img.CGImage 
                                            scale:1.0 orientation: UIImageOrientationDownMirrored];

yourUIImageView.image = flippedImage;
Lloyd18
  • 1,679
  • 1
  • 18
  • 28
  • thank you so much. I had just problems with the statement imageView.image = img; but then change it to [testTest.newView setImage: img]; – Studie May 25 '12 at 14:11
  • overwriting? what are you mean? – Lloyd18 May 25 '12 at 15:12
  • I have a png, which is a triangle. So if I use your method not the triangle get the color but also the background of the image. At the end there is no triangle but a square which has got the color red – Studie May 29 '12 at 06:53
  • 1
    I've edit answer, but you should expressed understandable in your question next time. It was really hard to understand what you want. – Lloyd18 May 29 '12 at 08:49
  • Thanks. I'm just looking through this trying to understand it. One question I have is how is it getting flipped to start? – GreenKiwi Mar 21 '13 at 19:13
  • Because of last two strings. – Lloyd18 Mar 22 '13 at 06:25
  • Great answer. However this only selects the non-retina image, even on a retina device? – nicktones Oct 19 '13 at 21:46
  • @nicktones: Remove the ".png" suffix from the given example. This allows the app to determine which image is appropriate instead of being told exactly which image to use (it would be akin to "triangle@2x.png"). – James Nelson Jul 15 '14 at 18:40
  • The result is not good for retina screens... See http://stackoverflow.com/a/20750373/1670830 for a fix. – Colas Dec 09 '14 at 15:10
12

For swift 3.2 and 4

extension UIImageView{
    func changePngColorTo(color: UIColor){
        guard let image =  self.image else {return}
        self.image = image.withRenderingMode(.alwaysTemplate)
        self.tintColor = color
    }
}

Use :

self.yourImageView.changePngColorTo(color: .red)
gamal
  • 1,587
  • 2
  • 21
  • 43
  • 1
    That doesn't change the color of the UIImage. Rather the image view is rendering it with a different color. – Steve Kuo Jul 21 '18 at 23:33
8

Details

  • Xcode 10.2.1 (10E1001), Swift 5

Way 1. Extension UIImage

source: https://stackoverflow.com/a/40177870/4488252

extension UIImage {

    convenience init?(imageName: String) {
        self.init(named: imageName)
        accessibilityIdentifier = imageName
    }

    // https://stackoverflow.com/a/40177870/4488252
    func imageWithColor (newColor: UIColor?) -> UIImage? {

        if let newColor = newColor {
            UIGraphicsBeginImageContextWithOptions(size, false, scale)

            let context = UIGraphicsGetCurrentContext()!
            context.translateBy(x: 0, y: size.height)
            context.scaleBy(x: 1.0, y: -1.0)
            context.setBlendMode(.normal)

            let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
            context.clip(to: rect, mask: cgImage!)

            newColor.setFill()
            context.fill(rect)

            let newImage = UIGraphicsGetImageFromCurrentImageContext()!
            UIGraphicsEndImageContext()
            newImage.accessibilityIdentifier = accessibilityIdentifier
            return newImage
        }

        if let accessibilityIdentifier = accessibilityIdentifier {
            return UIImage(imageName: accessibilityIdentifier)
        }

        return self
    }
}

Usage

let imageView = UIImageView(frame: CGRect(x: 40, y: 250, width: 40, height: 40))
view.addSubview(imageView)
// Set color
imageView.image = UIImage(imageName: "Apple")?.imageWithColor(newColor: UIColor.blue)
// Reset color
//imageView.image = imageView.image?.imageWithColor(newColor: nil)

Way 2. Extension UIImageView

extension UIImageView {

    var imageColor: UIColor? {
        set (newValue) {
            guard let image = image else { return }
            if newValue != nil {
                self.image = image.withRenderingMode(.alwaysTemplate)
                tintColor = newValue
            } else {
                self.image = image.withRenderingMode(.alwaysOriginal)
                tintColor = UIColor.clear
            }
        }
        get { return tintColor }
    }
}

Usage

let imageView = UIImageView(frame: CGRect(x: 40, y: 250, width: 40, height: 40))
view.addSubview(imageView)
imageView.image = UIImage(imageName: "Apple")
// Set color
imageView.imageColor = UIColor.green
// Reset color
//imageView.imageColor = nil

Full sample

Do not forget to paste here all code which placed above

import UIKit

class ImageView: UIImageView {
    enum ImageColorTransformType {
        case none, imageExtension, imageViewExtension
    }
    var imageColorTransformType = ImageColorTransformType.none
}

class ViewController: UIViewController {

    weak var colorSwitchButton: UIBarButtonItem?

    private var imageViews = [ImageView]()
    private var appleImage: UIImage { return UIImage(imageName: "apple")! }
    private var redAppleImage: UIImage { return UIImage(imageName: "red_apple")! }

    override func viewDidLoad() {
        super.viewDidLoad()
        createNewImageView(x: 40, y:100, image:appleImage, imageColorTransformType: .none)
        createNewImageView(x: 100, y:100, image:appleImage, imageColorTransformType: .imageExtension)
        createNewImageView(x: 160, y:100, image:appleImage, imageColorTransformType: .imageViewExtension)

        createNewImageView(x: 40, y:160, image:redAppleImage, imageColorTransformType: .none)
        createNewImageView(x: 100, y:160, image:redAppleImage, imageColorTransformType: .imageExtension)
        createNewImageView(x: 160, y:160, image:redAppleImage, imageColorTransformType: .imageViewExtension)

        let buttonItem = UIBarButtonItem(title: "switch", style: .plain, target: self,
                                         action: #selector(colorSwitchButtonTouchedUpInside(_:)))
        navigationItem.rightBarButtonItem = buttonItem
        colorSwitchButton = buttonItem
        useOriginalColors = false
    }

    private func createNewImageView(x:CGFloat, y: CGFloat, image: UIImage, imageColorTransformType: ImageView.ImageColorTransformType) {
        let imageView = ImageView(frame: CGRect(x: x, y: y, width: 40, height: 40))
        imageView.image = image
        imageView.imageColorTransformType = imageColorTransformType
        imageViews.append(imageView)
        view.addSubview(imageView)
    }

    private var _useOriginalColors = false
    private var useOriginalColors: Bool {
        set(value) {
            _useOriginalColors = value
            if (value) {
                navigationItem.title = "Original colors"
                for imageView in imageViews {
                    switch imageView.imageColorTransformType {
                    case .imageExtension: imageView.image = imageView.image?.imageWithColor(newColor: nil)
                    case .imageViewExtension: imageView.imageColor = nil
                    case .none: break
                    }
                }
            } else {
                navigationItem.title = "Template colors"
                for imageView in imageViews {
                    switch imageView.imageColorTransformType {
                    case .imageExtension: imageView.image = imageView.image?.imageWithColor(newColor: UIColor.blue)
                    case .imageViewExtension: imageView.imageColor = UIColor.green
                    case .none: break
                    }
                }
            }
        }
        get { return _useOriginalColors }
    }

    @objc func colorSwitchButtonTouchedUpInside(_ sender: Any) { useOriginalColors = !useOriginalColors }
}

Storyboard

enter image description here

Result

enter image description here enter image description here

Vasily Bodnarchuk
  • 24,482
  • 9
  • 132
  • 127
4

You can also do this in swift with the following code:

// language: Swift
let tintedImage = UIImageView(image: UIImage(named:"whatever")!.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate))

tintedImage.tintColor = UIColor.redColor()
Nagendra Rao
  • 7,016
  • 5
  • 54
  • 92
Bob Mosby
  • 101
  • 2
3

Swift + Interface builder (storyboard)

If you added the UIImageView in the interface builder:

myIcon.image = myIcon.image!.withRenderingMode(UIImageRenderingMode.alwaysTemplate)
myIcon.tintColor = UIColor.red // your color

where myIcon is an outlet from your storyboard, ex: @IBOutlet weak var myIcon: UIImageView!

lenooh
  • 10,364
  • 5
  • 58
  • 49
1

Change the color of the image in UIImageView:

public extension UIImageView {
    func tintImage(color: UIColor) {
        image = image?.tint(color: color)
    }
}

Just call the method:

imageView.tintImage(color: .red)
Umair Ali
  • 758
  • 8
  • 17
0

To add to skywinder's answer

You can also do this on a button:

UIImage *image = [UIImage imageNamed:@"foo.png"];
[myButton setImage:[image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal];
[myButton setTintColor:[UIColor redColor]];
devjme
  • 684
  • 6
  • 12