How to change the color of an UIImage
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
Result
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
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)
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;