How can I change image tintColor in iOS and WatchKit - ios

I have an UIImageView called "theImageView", with UIImage in a single color (transparent background) just like the left black heart below. How can I change the tint color of this image programmatically in iOS 7 or above, as per the tint method used in the iOS 7+ Navigation Bar icons?
Can this method also work in WatchKit for an Apple Watch app?

iOS
For an iOS app, in Swift 3, 4 or 5:
theImageView.image = theImageView.image?.withRenderingMode(.alwaysTemplate)
theImageView.tintColor = UIColor.red
For Swift 2:
theImageView.image = theImageView.image?.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
theImageView.tintColor = UIColor.redColor()
Meanwhile, the modern Objective-C solution is:
theImageView.image = [theImageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[theImageView setTintColor:[UIColor redColor]];
Watchkit
In WatchKit for Apple Watch apps, you can set the tint color for a template image.
You must add your image to an Asset Catalog in your WatchKit App, and set the image set to be rendered as a Template Image in the Attributes Inspector. Unlike for an iPhone app, you cannot set the template rendering in code in the WatchKit Extension at present.
Set that image to be used in your WKInterfaceImage in interface builder for your app
Create an IBOutlet in your WKInterfaceController for the WKInterfaceImage called 'theImage'...
To then set the tint color in Swift 3 or 4:
theImage.setTintColor(UIColor.red)
Swift 2:
theImage.setTintColor(UIColor.redColor())
To then set the tint color in Objective-C:
[self.theImage setTintColor:[UIColor redColor]];
If you use a template image and do not apply a tint colour, the Global Tint for your WatchKit app will be applied. If you have not set a Global Tint, theImage will be tinted light blue by default when used as a template image.

Here's a category that should do the trick
#interface UIImage(Overlay)
#end
#implementation UIImage(Overlay)
- (UIImage *)imageWithColor:(UIColor *)color1
{
UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0, self.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextSetBlendMode(context, kCGBlendModeNormal);
CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
CGContextClipToMask(context, rect, self.CGImage);
[color1 setFill];
CGContextFillRect(context, rect);
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
#end
so you would do:
theImageView.image = [theImageView.image imageWithColor:[UIColor redColor]];

I had to do this in Swift using an extension.
I thought I'd share how I did it:
extension UIImage {
func imageWithColor(color1: UIColor) -> UIImage {
UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
color1.setFill()
let context = UIGraphicsGetCurrentContext() as CGContextRef
CGContextTranslateCTM(context, 0, self.size.height)
CGContextScaleCTM(context, 1.0, -1.0);
CGContextSetBlendMode(context, CGBlendMode.Normal)
let rect = CGRectMake(0, 0, self.size.width, self.size.height) as CGRect
CGContextClipToMask(context, rect, self.CGImage)
CGContextFillRect(context, rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext() as UIImage
UIGraphicsEndImageContext()
return newImage
}
}
Usage:
theImageView.image = theImageView.image.imageWithColor(UIColor.redColor())
Swift 4
extension UIImage {
func imageWithColor(color1: UIColor) -> UIImage {
UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
color1.setFill()
let context = UIGraphicsGetCurrentContext()
context?.translateBy(x: 0, y: self.size.height)
context?.scaleBy(x: 1.0, y: -1.0)
context?.setBlendMode(CGBlendMode.normal)
let rect = CGRect(origin: .zero, size: CGSize(width: self.size.width, height: self.size.height))
context?.clip(to: rect, mask: self.cgImage!)
context?.fill(rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
}
Usage:
theImageView.image = theImageView.image?.imageWithColor(color1: UIColor.red)

In storyboard and image Assets. you can change this two also:
Update the Render Mode to Template Image
Update the tint Color in Views.

If anyone care a solution without UIImageView:
// (Swift 3)
extension UIImage {
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
}
}

Swift 4
Change tint of UIImage SVG / PDF, that work for image with unique color :
import Foundation
// MARK: - UIImage extensions
public extension UIImage {
//
/// Tint Image
///
/// - Parameter fillColor: UIColor
/// - Returns: Image with tint color
func tint(with fillColor: UIColor) -> UIImage? {
let image = withRenderingMode(.alwaysTemplate)
UIGraphicsBeginImageContextWithOptions(size, false, scale)
fillColor.set()
image.draw(in: CGRect(origin: .zero, size: size))
guard let imageColored = UIGraphicsGetImageFromCurrentImageContext() else {
return nil
}
UIGraphicsEndImageContext()
return imageColored
}
}
Change tint of UIImageView, that work for image with unique color :
let imageView = UIImageView(frame: CGRect(x: 50, y: 50, width: 50, height: 50))
imageView.image = UIImage(named: "hello.png")!.withRenderingMode(.alwaysTemplate)
imageView.tintColor = .yellow
Change tint of UIImage for picture, use that :
import Foundation
// MARK: - Extensions UIImage
public extension UIImage {
/// Tint, Colorize image with given tint color
/// This is similar to Photoshop's "Color" layer blend mode
/// This is perfect for non-greyscale source images, and images that
/// have both highlights and shadows that should be preserved<br><br>
/// white will stay white and black will stay black as the lightness of
/// the image is preserved
///
/// - Parameter TintColor: Tint color
/// - Returns: Tinted image
public func tintImage(with fillColor: UIColor) -> UIImage {
return modifiedImage { context, rect in
// draw black background - workaround to preserve color of partially transparent pixels
context.setBlendMode(.normal)
UIColor.black.setFill()
context.fill(rect)
// draw original image
context.setBlendMode(.normal)
context.draw(cgImage!, in: rect)
// tint image (loosing alpha) - the luminosity of the original image is preserved
context.setBlendMode(.color)
fillColor.setFill()
context.fill(rect)
// mask by alpha values of original image
context.setBlendMode(.destinationIn)
context.draw(context.makeImage()!, in: rect)
}
}
/// Modified Image Context, apply modification on image
///
/// - Parameter draw: (CGContext, CGRect) -> ())
/// - Returns: UIImage
fileprivate func modifiedImage(_ draw: (CGContext, CGRect) -> ()) -> UIImage {
// using scale correctly preserves retina images
UIGraphicsBeginImageContextWithOptions(size, false, scale)
let context: CGContext! = UIGraphicsGetCurrentContext()
assert(context != nil)
// correctly rotate image
context.translateBy(x: 0, y: size.height)
context.scaleBy(x: 1.0, y: -1.0)
let rect = CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height)
draw(context, rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}
}

With Swift
let commentImageView = UIImageView(frame: CGRectMake(100, 100, 100, 100))
commentImageView.image = UIImage(named: "myimage.png")!.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
commentImageView.tintColor = UIColor.blackColor()
addSubview(commentImageView)

For swift 3 purposes
theImageView.image = theImageView.image!.withRenderingMode(.alwaysTemplate)
theImageView.tintColor = UIColor.red

Here's a simple extension that works for Swift 5:
extension UIImageView {
func setImageTintColor(_ color: UIColor) {
let tintedImage = self.image?.withRenderingMode(.alwaysTemplate)
self.image = tintedImage
self.tintColor = color
}
}
Usage:
myImageView.setImageTintColor(.systemBlue)

Also, for the above answers, in iOS 13 and later there is a clean way
let image = UIImage(named: "imageName")?.withTintColor(.white, renderingMode: .alwaysTemplate)

Try this
http://robots.thoughtbot.com/designing-for-ios-blending-modes
or
- (void)viewDidLoad
{
[super viewDidLoad];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 30, 300, 50)];
label.numberOfLines = 0;
label.font = [UIFont systemFontOfSize:13];
label.text = #"These checkmarks use the same gray checkmark image with a tintColor applied to the image view";
[self.view addSubview:label];
[self _createImageViewAtY:100 color:[UIColor purpleColor]];
}
- (void)_createImageViewAtY:(int)y color:(UIColor *)color {
UIImage *image = [[UIImage imageNamed:#"gray checkmark.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
CGRect frame = imageView.frame;
frame.origin.x = 100;
frame.origin.y = y;
imageView.frame = frame;
if (color)
imageView.tintColor = color;
[self.view addSubview:imageView];
}

For tinting the image of a UIButton
let image1 = "ic_shopping_cart_empty"
btn_Basket.setImage(UIImage(named: image1)?.withRenderingMode(.alwaysTemplate), for: .normal)
btn_Basket.setImage(UIImage(named: image1)?.withRenderingMode(.alwaysTemplate), for: .selected)
btn_Basket.imageView?.tintColor = UIColor(UIColor.Red)

iOS
Solution for doing it from Interface Builder, set templateImage param in keyPath and choose your tint color from IB
extension UIImageView {
// make template image with tint color
var templateImage: Bool {
set {
if newValue, let image = self.image {
let newImage = image.withRenderingMode(.alwaysTemplate)
self.image = newImage
}
} get {
return false
}
}
}

Take benefit of Extension in Swift :-
extension UIImageView {
func changeImageColor( color:UIColor) -> UIImage
{
image = image!.withRenderingMode(.alwaysTemplate)
tintColor = color
return image!
}
}
//Change color of logo
logoImage.image = logoImage.changeImageColor(color: .red)

Swift 3 version of extension answer from fuzz
func imageWithColor(color: UIColor) -> UIImage {
UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
color.setFill()
let context = UIGraphicsGetCurrentContext()! as CGContext
context.translateBy(x: 0, y: self.size.height)
context.scaleBy(x: 1.0, y: -1.0);
context.setBlendMode(.normal)
let rect = CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height) as CGRect
context.clip(to: rect, mask: self.cgImage!)
context.fill(rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()! as UIImage
UIGraphicsEndImageContext()
return newImage
}

With iOS 13 and above, you can simply use
let image = UIImage(named: "Heart")?.withRenderingMode(.alwaysTemplate)
if #available(iOS 13.0, *) {
imageView.image = image?.withTintColor(UIColor.white)
}

There is a native method for UIImage since iOS 13
let image = yourImage.withTintColor(.systemRed)

This is my UIImage extension and you can directly use changeTintColor function for an image.
extension UIImage {
func changeTintColor(color: UIColor) -> UIImage {
var newImage = self.withRenderingMode(.alwaysTemplate)
UIGraphicsBeginImageContextWithOptions(self.size, false, newImage.scale)
color.set()
newImage.draw(in: CGRect(x: 0.0, y: 0.0, width: self.size.width, height: self.size.height))
newImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
}
func changeColor(color: UIColor) -> UIImage {
let backgroundSize = self.size
UIGraphicsBeginImageContext(backgroundSize)
guard let context = UIGraphicsGetCurrentContext() else {
return self
}
var backgroundRect = CGRect()
backgroundRect.size = backgroundSize
backgroundRect.origin.x = 0
backgroundRect.origin.y = 0
var red: CGFloat = 0
var green: CGFloat = 0
var blue: CGFloat = 0
var alpha: CGFloat = 0
color.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
context.setFillColor(red: red, green: green, blue: blue, alpha: alpha)
context.translateBy(x: 0, y: backgroundSize.height)
context.scaleBy(x: 1.0, y: -1.0)
context.clip(to: CGRect(x: 0.0, y: 0.0, width: self.size.width, height: self.size.height),
mask: self.cgImage!)
context.fill(backgroundRect)
var imageRect = CGRect()
imageRect.size = self.size
imageRect.origin.x = (backgroundSize.width - self.size.width) / 2
imageRect.origin.y = (backgroundSize.height - self.size.height) / 2
context.setBlendMode(.multiply)
context.draw(self.cgImage!, in: imageRect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
}
Example usage like this
let image = UIImage(named: "sample_image")
imageView.image = image.changeTintColor(color: UIColor.red)
And you can use change changeColor function to change the image color

Swift 5
Redrawing image with background and fill color
extension UIImage {
func withBackground(color: UIColor, fill fillColor: UIColor) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, true, scale)
guard let ctx = UIGraphicsGetCurrentContext(), let image = cgImage else { return self }
defer { UIGraphicsEndImageContext() }
ctx.concatenate(CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: size.height))
let rect = CGRect(origin: .zero, size: size)
// draw background
ctx.setFillColor(color.cgColor)
ctx.fill(rect)
// draw image with fill color
ctx.clip(to: rect, mask: image)
ctx.setFillColor(fillColor.cgColor)
ctx.fill(rect)
return UIGraphicsGetImageFromCurrentImageContext() ?? self
}
}

Now i use this method based in Duncan Babbage response:
+ (UIImageView *) tintImageView: (UIImageView *)imageView withColor: (UIColor*) color{
imageView.image = [imageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[imageView setTintColor:color];
return imageView;
}

You can use this in Swift 3 if you have an image to replace the clear button
func addTextfieldRightView(){
let rightViewWidth:CGFloat = 30
let viewMax = self.searchTxt.frame.height
let buttonMax = self.searchTxt.frame.height - 16
let buttonView = UIView(frame: CGRect(
x: self.searchTxt.frame.width - rightViewWidth,
y: 0,
width: viewMax,
height: viewMax))
let myButton = UIButton(frame: CGRect(
x: (viewMax - buttonMax) / 2,
y: (viewMax - buttonMax) / 2,
width: buttonMax,
height: buttonMax))
myButton.setImage(UIImage(named: "BlueClear")!, for: .normal)
buttonView.addSubview(myButton)
let clearPressed = UITapGestureRecognizer(target: self, action: #selector(SearchVC.clearPressed(sender:)))
buttonView.isUserInteractionEnabled = true
buttonView.addGestureRecognizer(clearPressed)
myButton.addTarget(self, action: #selector(SearchVC.clearPressed(sender:)), for: .touchUpInside)
self.searchTxt.rightView = buttonView
self.searchTxt.rightViewMode = .whileEditing
}

Subclass which can be used from code and Interface Builder as well:
#implementation TintedImageView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self setup];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self setup];
}
return self;
}
-(void)setup {
self.image = [self.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
}
#end

profileImageView.image = theImageView.image!.withRenderingMode(.alwaysTemplate)
profileImageView.tintColor = UIColor.green
OR
First select Particular image in image asset and then select reddened as Template instead of Default and after that write line.
profileImageView.tintColor = UIColor.green

if you have any id for the SVG image, you can fill the colours with respect to the ID.
let image = SVGKImage(named: "iconName")
let svgIMGV = SVGKFastImageView(frame: self.imgView.frame)
svgIMGV.image = image
svgIMGV.fillTintColor(colorImage: UIColor.red, iconID: "Bank")
// Add in extension SVGKImageView
extension SVGKImageView {
func fillTintColor(colorImage: UIColor, iconID: String) {
if self.image != nil && self.image.caLayerTree != nil {
print(self.image.caLayerTree.sublayers)
guard let sublayers = self.image.caLayerTree.sublayers else { return }
fillRecursively(sublayers: sublayers, color: colorImage, iconID: iconID)
}
}
private func fillRecursively(sublayers: [CALayer], color: UIColor, iconID: String, hasFoundLayer: Bool) {
var isLayerFound = false
for layer in sublayers {
if let l = layer as? CAShapeLayer {
print(l.name)
//IF you want to color the specific shapelayer by id else remove the l.name == "myID" validation
if let name = l.name, hasFoundLayer == true && name == "myID" {
self.colorThatImageWIthColor(color: color, layer: l)
print("Colouring FInished")
}
} else {
if layer.name == iconID {
if let innerSublayer = layer.sublayers as? [CAShapeLayer] {
fillRecursively(sublayers: innerSublayer, color: color, iconID: iconID, hasFoundLayer: true )
print("FOund")
}
} else {
if let l = layer as? CALayer, let sub = l.sublayers {
fillRecursively(sublayers: sub, color: color, iconID: iconID, hasFoundLayer: false)
}
}
}
}
}
func colorThatImageWIthColor(color: UIColor, layer: CAShapeLayer) {
if layer.strokeColor != nil {
layer.strokeColor = color.cgColor
}
if layer.fillColor != nil {
layer.fillColor = color.cgColor
}
}
}
OR Checkout this example.
https://github.com/ravisfortune/SVGDEMO

let navHeight = self.navigationController?.navigationBar.frame.height;
let menuBtn = UIButton(type: .custom)
menuBtn.frame = CGRect(x: 0, y: 0, width: 45, height: navHeight!)
menuBtn.setImage(UIImage(named:"image_name")!.withRenderingMode(.alwaysTemplate), for: .normal)
menuBtn.tintColor = .black

Related

Draw border of certain color around colored UIImage in tab bar

In order to understand my problem I will start with a short description of my goal:
In the center of my tab bar I deliberately use a usually too big image (a circle) which extends over the tab bar (the tab bar's background color is white) so it laps over the top border of the tab bar. Since all UITabBarItems' default color is a light gray (apparently it is neither UIColor.lightGray nor .darkGray) and I would like to change the color of this (and only this) UITabBarItem (or rather the image considering this is the only thing which can be seen of this UITabBarItem) to white I've used the following extension/function which works fine:
extension UIImage {
func tabBarImageWithCustomTint(tintColor: UIColor) -> UIImage {
UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
let context: CGContext = UIGraphicsGetCurrentContext()!
context.translateBy(x: 0, y: self.size.height)
context.scaleBy(x: 1.0, y: -1.0)
context.setBlendMode(CGBlendMode(rawValue: 1)!)
let rect: CGRect = CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height)
context.clip(to: rect, mask: self.cgImage!)
tintColor.setFill()
context.fill(rect)
var newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
newImage = newImage.withRenderingMode(UIImageRenderingMode.alwaysOriginal)
return newImage
}
}
Link to question where I found this extension
As both the tint color of the image and the background color of the tab bar are white, I would now like to add a border of red color to the now white image. Luckily, I managed to find another question on stackoverflow which answered this question (although I must add that I am not entirely content with this extension because it leaves a very small space between the UIImage and the border):
extension UIImage {
func roundedImageWithBorder(width: CGFloat, color: UIColor) -> UIImage? {
let square = CGSize(width: min(size.width, size.height) + width * 2, height: min(size.width, size.height) + width * 2)
let imageView = UIImageView(frame: CGRect(origin: CGPoint(x: 0, y: 0), size: square))
imageView.contentMode = .center
imageView.image = self
imageView.layer.cornerRadius = square.width/2
imageView.layer.masksToBounds = true
imageView.layer.borderWidth = width
imageView.layer.borderColor = color.cgColor
UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, false, scale)
guard let context = UIGraphicsGetCurrentContext() else { return nil }
imageView.layer.render(in: context)
let result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return result
}
}
My problem now is if I use the function consecutively like this...:
let tabRecordButton = UIImage(named: "circle").tabBarImageWithCustomTint(tintColor: .white).roundedImageWithBorder(width: 1, color: .red)
..., the border is drawn but the UITabBarItem's tint color goes back to this default gray aforementioned (not even the border is red).
So my question: Is there a way I can do both, i.e. color the image white and the border red in my UITabBar?
You have to add this line result = result.withRenderingMode(UIImageRenderingMode.alwaysOriginal) in your second extension as well, if you omit this line then your image will take the tint from your tabBar, that is your original issue
replace your roundedImageWithBorder extension method implementation with this one
func roundedImageWithBorder(width: CGFloat, color: UIColor) -> UIImage? {
let square = CGSize(width: min(size.width, size.height) + width * 2, height: min(size.width, size.height) + width * 2)
let imageView = UIImageView(frame: CGRect(origin: CGPoint(x: 0, y: 0), size: square))
imageView.contentMode = .center
imageView.image = self
imageView.layer.cornerRadius = square.width/2
imageView.layer.masksToBounds = true
imageView.layer.borderWidth = width
imageView.layer.borderColor = color.cgColor
UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, false, scale)
guard let context = UIGraphicsGetCurrentContext() else { return nil }
imageView.layer.render(in: context)
var result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
result = result?.withRenderingMode(UIImageRenderingMode.alwaysOriginal)
return result
}
Testing
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.tabBarItem.selectedImage = UIImage(named: "icono-menu")?.tabBarImageWithCustomTint(tintColor: UIColor.magenta).roundedImageWithBorder(width: 1, color: UIColor.blue)
self.tabBarController?.tabBar.tintColor = UIColor.red //note that the tintColor of the tabBar is red
}
Result

How do I draw on an image in Swift?

I need to be able to programmatically draw on an image, and save that image for later use. Say, draw a line on specific x and y coordinates on the image, save the image, and display it onto a simple view controller. How would I go about doing this in Swift? (Preferably Swift 2, I am still in development and haven't updated my mac to Sierra)
Update: Possibly something to do with converting a UIImage to a CGLayer, drawing on it, and then converting it back to a UIImage.
All you need to do is create and get an Image Context object and access all its powerful drawing methods. You can learn more about the CGContext object features here.
This function draws a line and a circle on an UIImage and returns the modified image:
Swift 4
func drawOnImage(_ image: UIImage) -> UIImage {
// Create a context of the starting image size and set it as the current one
UIGraphicsBeginImageContext(image.size)
// Draw the starting image in the current context as background
image.draw(at: CGPoint.zero)
// Get the current context
let context = UIGraphicsGetCurrentContext()!
// Draw a red line
context.setLineWidth(2.0)
context.setStrokeColor(UIColor.red.cgColor)
context.move(to: CGPoint(x: 100, y: 100))
context.addLine(to: CGPoint(x: 200, y: 200))
context.strokePath()
// Draw a transparent green Circle
context.setStrokeColor(UIColor.green.cgColor)
context.setAlpha(0.5)
context.setLineWidth(10.0)
context.addEllipse(in: CGRect(x: 100, y: 100, width: 100, height: 100))
context.drawPath(using: .stroke) // or .fillStroke if need filling
// Save the context as a new UIImage
let myImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
// Return modified image
return myImage
}
It's simple:
Make an image graphics context. (Before iOS 10, you would do this by calling UIGraphicsBeginImageContextWithOptions. In iOS 10 there's another way, UIGraphicsImageRenderer, but you don't have to use it if you don't want to.)
Draw (i.e. copy) the image into the context. (UIImage actually has draw... methods for this very purpose.)
Draw your line into the context. (There are CGContext functions for this.)
Extract the resulting image from the context. (For example, if you used UIGraphicsBeginImageContextWithOptions, you would use UIGraphicsGetImageFromCurrentImageContext.) Then close the context.
Details
Xcode 9.1, Swift 4
Solution
extension UIImage
extension UIImage {
typealias RectCalculationClosure = (_ parentSize: CGSize, _ newImageSize: CGSize)->(CGRect)
func with(image named: String, rectCalculation: RectCalculationClosure) -> UIImage {
return with(image: UIImage(named: named), rectCalculation: rectCalculation)
}
func with(image: UIImage?, rectCalculation: RectCalculationClosure) -> UIImage {
if let image = image {
UIGraphicsBeginImageContext(size)
draw(in: CGRect(origin: .zero, size: size))
image.draw(in: rectCalculation(size, image.size))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
return self
}
}
extension UIImageView
extension UIImageView {
enum ImageAddingMode {
case changeOriginalImage
case addSubview
}
func drawOnCurrentImage(anotherImage: UIImage?, mode: ImageAddingMode, rectCalculation: UIImage.RectCalculationClosure) {
guard let image = image else {
return
}
switch mode {
case .changeOriginalImage:
self.image = image.with(image: anotherImage, rectCalculation: rectCalculation)
case .addSubview:
let newImageView = UIImageView(frame: rectCalculation(frame.size, image.size))
newImageView.image = anotherImage
addSubview(newImageView)
}
}
}
Images samples
Parent Image:
Child Image:
Usage example 1
func sample1(imageView: UIImageView) {
imageView.contentMode = .scaleAspectFit
imageView.image = UIImage(named: "parent")?.with(image: "child") { parentSize, newImageSize in
print("parentSize = \(parentSize)")
print("newImageSize = \(newImageSize)")
return CGRect(x: 50, y: 50, width: 90, height: 90)
}
}
Result 1
Usage example 2
func sample2(imageView: UIImageView) {
imageView.contentMode = .scaleAspectFit
imageView.image = UIImage(named: "parent")
imageView.drawOnCurrentImage(anotherImage: UIImage(named: "child"), mode: .changeOriginalImage) { parentSize, newImageSize in
print("parentSize = \(parentSize)")
print("newImageSize = \(newImageSize)")
let sideLength:CGFloat = 90
let indent:CGFloat = 50
return CGRect(x: parentSize.width-sideLength-indent, y: parentSize.height-sideLength-indent, width: sideLength, height: sideLength)
}
}
Result 2
Usage example 3
func sample3(imageView: UIImageView) {
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.image = UIImage(named: "parent")
imageView.drawOnCurrentImage(anotherImage: UIImage(named: "child"), mode: .addSubview) { parentSize, newImageSize in
print("parentSize = \(parentSize)")
print("newImageSize = \(newImageSize)")
let sideLength:CGFloat = 90
let indent:CGFloat = 15
return CGRect(x: parentSize.width-sideLength-indent, y: indent, width: sideLength, height: sideLength)
}
}
Result 3
Full sample code
Don't forget to add Solution code here
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let imageView = UIImageView(frame: UIScreen.main.bounds)
view.addSubview(imageView)
sample1(imageView: imageView)
// sample2(imageView: imageView)
// sample3(imageView: imageView)
}
func sample1(imageView: UIImageView) {
imageView.contentMode = .scaleAspectFit
imageView.image = UIImage(named: "parent")?.with(image: "child") { parentSize, newImageSize in
print("parentSize = \(parentSize)")
print("newImageSize = \(newImageSize)")
return CGRect(x: 50, y: 50, width: 90, height: 90)
}
}
func sample2(imageView: UIImageView) {
imageView.contentMode = .scaleAspectFit
imageView.image = UIImage(named: "parent")
imageView.drawOnCurrentImage(anotherImage: UIImage(named: "child"), mode: .changeOriginalImage) { parentSize, newImageSize in
print("parentSize = \(parentSize)")
print("newImageSize = \(newImageSize)")
let sideLength:CGFloat = 90
let indent:CGFloat = 50
return CGRect(x: parentSize.width-sideLength-indent, y: parentSize.height-sideLength-indent, width: sideLength, height: sideLength)
}
}
func sample3(imageView: UIImageView) {
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.image = UIImage(named: "parent")
imageView.drawOnCurrentImage(anotherImage: UIImage(named: "child"), mode: .addSubview) { parentSize, newImageSize in
print("parentSize = \(parentSize)")
print("newImageSize = \(newImageSize)")
let sideLength:CGFloat = 90
let indent:CGFloat = 15
return CGRect(x: parentSize.width-sideLength-indent, y: indent, width: sideLength, height: sideLength)
}
}
}
Since iOS 10 you can use the UIGraphicImageRenderer, which has a better syntax and has some great features!
Swift 4
let renderer = UIGraphicsImageRenderer(size: view.bounds.size)
let image = renderer.image { context in
// draw your image into your view
context.cgContext.draw(UIImage(named: "myImage")!.cgImage!, in: view.frame)
// draw even more...
context.cgContext.setFillColor(UIColor.red.cgColor)
context.cgContext.setStrokeColor(UIColor.black.cgColor)
context.cgContext.setLineWidth(10)
context.cgContext.addRect(view.frame)
context.cgContext.drawPath(using: .fillStroke)
}
Updated Answer: Once you get the From and To coordinates, here is how to draw a line in a UIImage with those coordinates. From and To coordinates are in image pixels.
func drawLineOnImage(size: CGSize, image: UIImage, from: CGPoint, to: CGPoint) -> UIImage {
// begin a graphics context of sufficient size
UIGraphicsBeginImageContext(size)
// draw original image into the context
image.drawAtPoint(CGPointZero)
// get the context for CoreGraphics
let context = UIGraphicsGetCurrentContext()
// set stroking width and color of the context
CGContextSetLineWidth(context, 1.0)
CGContextSetStrokeColorWithColor(context, UIColor.blueColor().CGColor)
// set stroking from & to coordinates of the context
CGContextMoveToPoint(context, from.x, from.y)
CGContextAddLineToPoint(context, to.x, to.y)
// apply the stroke to the context
CGContextStrokePath(context)
// get the image from the graphics context
let resultImage = UIGraphicsGetImageFromCurrentImageContext()
// end the graphics context
UIGraphicsEndImageContext()
return resultImage }

How to color a white image in Swift to another color?

I would like to color a white icon to another color in run time, I was trying to use the method taken from here, but without success:
func maskImageView() {
var maskImageSize = CGSizeMake(self.downloadImageView.frame.width, self.downloadImageView.frame.height)
UIGraphicsBeginImageContextWithOptions(maskImageSize, false, 0.0)
var color = UIColor(white: 1.0, alpha: 1.0)
color.setFill()
var rect = CGRectMake(0, 0, self.downloadImageView.frame.width, self.downloadImageView.frame.height)
UIRectFill(rect)
color = BrandColors.BRAND_FIRST_COLOR
color.setFill()
rect = CGRectMake((self.downloadImageView.frame.width/2)-100, (self.downloadImageView.frame.height/2)-100, 200, 200)
UIRectFill(rect)
var maskImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
var maskLayer = CALayer()
maskLayer.frame = CGRectMake(0, 0, self.downloadImageView.bounds.width, self.downloadImageView.bounds.height)
maskLayer.contents = maskImage.CGImage
maskLayer.contentsRect = CGRectMake(0, 0, self.downloadImageView.bounds.width, self.downloadImageView.bounds.height)
self.downloadImageView.layer.mask = maskLayer;
}
I can't actually figure out how this masking thing works. What am I doing wrong?
I was able to achieve this task with the following method:
func maskDownloadImageView() {
downloadImageView.image = downloadImageView.image?.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
downloadImageView.tintColor = BrandColors.BRAND_FIRST_COLOR
}
There is no need in using masking.
Try this.
func fillImage(image : UIImage! ,withColor color : UIColor!) -> UIImage!
{
// Create the proper sized rect
let imageRect = CGRectMake(0, 0, image.size.width, image.size.height)
// Create a new bitmap context
let colorSpace:CGColorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGBitmapInfo(CGImageAlphaInfo.PremultipliedLast.rawValue)
let context = CGBitmapContextCreate(nil, Int(imageRect.size.width), Int(imageRect.size.height), 8, 0, colorSpace, bitmapInfo)
// Use the passed in image as a clipping mask
CGContextClipToMask(context, imageRect, image.CGImage)
// Set the fill color
CGContextSetFillColorWithColor(context, color.CGColor)
// Fill with color
CGContextFillRect(context, imageRect)
// Generate a new image
let newCGImage = CGBitmapContextCreateImage(context)
let newImage = UIImage(CGImage: newCGImage)
return newImage;
}
To mask transparent image try this:
func maskImageWithColor(color : UIColor!) -> UIImage {
UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
if let context: CGContextRef = UIGraphicsGetCurrentContext() {
CGContextTranslateCTM(context, 0, self.size.height)
CGContextScaleCTM(context, 1.0, -1.0)
CGContextSetBlendMode(context, .Normal)
let rect: CGRect = CGRectMake(0, 0, self.size.width, self.size.height)
// To use gradient, add CGColor to Array
let colors: [CGColor] = [color.CGColor]
let colorsPointer = UnsafeMutablePointer<UnsafePointer<Void>>(colors)
if let colorsCFArray = CFArrayCreate(nil, colorsPointer, colors.count, nil) {
if let space: CGColorSpaceRef = CGColorSpaceCreateDeviceRGB() {
if let gradient: CGGradientRef = CGGradientCreateWithColors(space, colorsCFArray, nil) {
// Apply gradient
CGContextClipToMask(context, rect, self.CGImage)
CGContextDrawLinearGradient(context, gradient, CGPointMake(0,0), CGPointMake(0, self.size.height), .DrawsBeforeStartLocation)
let coloredImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return coloredImage;
}
}
}
}
return self
}
You can use gradient just adding more CGColor in the array
Swift 4 version of Emil Adz answer for the lazy.
func maskDownloadImageView() {
downloadImageView.image = downloadImageView.image?.withRenderingMode(UIImage.RenderingMode.alwaysTemplate)
downloadImageView.tintColor = BrandColors.BRAND_FIRST_COLOR
}

How can I change image tintColor

I'm receiving image from a server, then based on a color chosen by the user, the image color will be changed.
I tried the following :
_sketchImageView.image = [_sketchImageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[_sketchImageView setTintColor:color];
i got the opposite of my goal (the white color outside UIImage is colored with the chosen color).
what is going wrong?
i need to do the same in this question,the provided solution doesn't solve my case.
How can I change image tintColor in iOS and WatchKit
Try to generate new image for yourself
UIImage *newImage = [_sketchImageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UIGraphicsBeginImageContextWithOptions(image.size, NO, newImage.scale);
[yourTintColor set];
[newImage drawInRect:CGRectMake(0, 0, image.size.width, newImage.size.height)];
newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
_sketchImageView.image = newImage;
And use it.
Good luck
======= UPDATE =======
This solution will only change color of all pixel's image.
Example: we have a book image: http://pngimg.com/upload/book_PNG2113.png
And after running above code (exp: TintColor is RED). We have:
SO: how your image is depends on how you designed it
In Swift you can use this extension: [Based on #VietHung's objective-c solution]
Swift 5:
extension UIImage {
func imageWithColor(color: UIColor) -> UIImage? {
var image = withRenderingMode(.alwaysTemplate)
UIGraphicsBeginImageContextWithOptions(size, false, scale)
color.set()
image.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
image = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return image
}
}
Previous Swift version:
extension UIImage {
func imageWithColor(color: UIColor) -> UIImage? {
var image = imageWithRenderingMode(.AlwaysTemplate)
UIGraphicsBeginImageContextWithOptions(size, false, scale)
color.set()
image.drawInRect(CGRect(x: 0, y: 0, width: size.width, height: size.height))
image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
In swift 2.0 you can use this
let image = UIImage(named:"your image name")?.imageWithRenderingMode(.AlwaysTemplate)
let yourimageView.tintColor = UIColor.redColor()
yourimageView.image = image
In swift 3.0 you can use this
let image = UIImage(named:"your image name")?.withRenderingMode(.alwaysTemplate)
let yourimageView.tintColor = UIColor.red
yourimageView.image = image
Try something like this
UIImage *originalImage = _sketchImageView.image
UIImage *newImage = [originalImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,50,50)]; // your image size
imageView.tintColor = [UIColor redColor]; // or whatever color that has been selected
imageView.image = newImage;
_sketchImageView.image = imageView.image;
Hope this helps.
In Swift 3.0 you can use this extension: [Based on #VietHung's objective-c solution]
extension UIImage {
func imageWithColor(_ color: UIColor) -> UIImage? {
var image = imageWithRenderingMode(.alwaysTemplate)
UIGraphicsBeginImageContextWithOptions(size, false, scale)
color.set()
image.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
For Swift 3.0, I made a custom subclass of UIImageView called TintedUIImageView. Now the image uses whatever tint color is set in interface builder or code
class TintedUIImageView: UIImageView {
override func awakeFromNib() {
if let image = self.image {
self.image = image.withRenderingMode(.alwaysTemplate)
}
}
}
You can try:
_sketchImageView.image = [self imageNamed:#"imageName" withColor:[UIColor blackColor]];
- (UIImage *)imageNamed:(NSString *)name withColor:(UIColor *)color
{
// load the image
//NSString *name = #"badge.png";
UIImage *img = [UIImage imageNamed:name];
// begin a new image context, to draw our colored image onto
UIGraphicsBeginImageContext(img.size);
// get a reference to that context we created
CGContextRef context = UIGraphicsGetCurrentContext();
// set the fill color
[color setFill];
// translate/flip the graphics context (for transforming from CG* coords to UI* coords
CGContextTranslateCTM(context, 0, img.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
// set the blend mode to color burn, and the original image
CGContextSetBlendMode(context, kCGBlendModeColorBurn);
CGRect rect = CGRectMake(0, 0, img.size.width, img.size.height);
CGContextDrawImage(context, rect, img.CGImage);
// set a mask that matches the shape of the image, then draw (color burn) a colored rectangle
CGContextClipToMask(context, rect, img.CGImage);
CGContextAddRect(context, rect);
CGContextDrawPath(context,kCGPathFill);
// generate a new UIImage from the graphics context we drew onto
UIImage *coloredImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//return the color-burned image
return coloredImg;
}
Try setting the tint color on the superview of the image view. E.g. [self.view setTintColor:color];
in Swift 4 you can simply make an extension like that:
import UIKit
extension UIImageView {
func tintImageColor(color: UIColor) {
guard let image = image else { return }
self.image = image.withRenderingMode(UIImageRenderingMode.alwaysTemplate)
self.tintColor = color
}
}
- SWIFT 4
extension UIImage {
func imageWithColor(_ color: UIColor) -> UIImage? {
var image: UIImage? = withRenderingMode(.alwaysTemplate)
UIGraphicsBeginImageContextWithOptions(size, false, scale)
color.set()
image?.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
Here's how I apply and use tints in IOS 9 with Swift.
//apply a color to an image
//ref - http://stackoverflow.com/questions/28427935/how-can-i-change-image-tintcolor
//ref - https://www.captechconsulting.com/blogs/ios-7-tutorial-series-tint-color-and-easy-app-theming
func getTintedImage() -> UIImageView {
var image : UIImage;
var imageView : UIImageView;
image = UIImage(named: "someAsset")!;
let size : CGSize = image.size;
let frame : CGRect = CGRectMake((UIScreen.mainScreen().bounds.width-86)/2, 600, size.width, size.height);
let redCover : UIView = UIView(frame: frame);
redCover.backgroundColor = UIColor.redColor();
redCover.layer.opacity = 0.75;
imageView = UIImageView();
imageView.image = image.imageWithRenderingMode(UIImageRenderingMode.Automatic);
imageView.addSubview(redCover);
return imageView;
}
One thing you can do is, just add your images to Assets folder in XCode and then change the rendering mode to Template Image, so whenever you change the tint color of UIImageView, it will automatically makes change to image.
Check this link out -> https://www.google.co.in/url?sa=i&rct=j&q=&esrc=s&source=images&cd=&cad=rja&uact=8&ved=0ahUKEwiM0YXO0ejTAhUIQ48KHfGpBpgQjRwIBw&url=https%3A%2F%2Fkrakendev.io%2Fblog%2F4-xcode-asset-catalog-secrets-you-need-to-know&psig=AFQjCNGnAzVn92pCqM8612o1R0J9q1y7cw&ust=1494619445516498
let image = UIImage(named: "i m a g e n a m e")?.withRenderingMode(.alwaysTemplate)
imageView.tintColor = UIColor.white // Change to require color
imageView.image = image
Try this
iOS 13.4 and above
UIImage *image = [UIImage imageNamed:#"placeHolderIcon"];
[image imageWithTintColor:[UIColor whiteColor] renderingMode: UIImageRenderingModeAlwaysTemplate];

UIImage animationImages tint color?

Is there a way to tint the images in an animation?
I know I can tint a single image like this:
var imageOne:UIImage = UIImage(named: "pullto_1.png")!;
imageOne = imageOne.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate);
refSequence.image = imageOne;
But when I try to do it like this it just dosen't work:
var imageOne:UIImage = UIImage(named: "pullto_1.png")!;
imageOne = imageOne.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
var image2:UIImage = UIImage(named: "pullto_2.png")!;
image2 = image2.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
var image3:UIImage = UIImage(named: "pullto_3.png")!;
image3 = image3.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
var image4:UIImage = UIImage(named: "pullto_4.png")!;
image4 = image4.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
refSequence.animationImages = NSArray(objects: imageOne,
image2,
image3,
image4
);
refSequence.animationDuration = 1.4;
refSequence.animationRepeatCount = 99;
refSequence.startAnimating();
Am I doing something wrong? Is there some way to tint the images in the animation?
Thanks
Ok, i hoped that there is a simpler solution but this is what I ended up doing:
This function will create a new image with the wanted color:
func imageWithColor(img:UIImage, color:UIColor)->UIImage{
UIGraphicsBeginImageContextWithOptions(img.size, false, img.scale);
var context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0, img.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextSetBlendMode(context, kCGBlendModeNormal);
var rect = CGRectMake(0, 0, img.size.width, img.size.height);
CGContextClipToMask(context, rect, img.CGImage)
color.setFill();
CGContextFillRect(context, rect);
var newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
And then you can call it like this:
var imageOne:UIImage = UIImage(named: "pullto_1.png")!;
imageOne = imageWithColor(imageOne, color: UIColor.redColor());
var image2:UIImage = UIImage(named: "pullto_2.png")!;
image2 = imageWithColor(image2, color: UIColor.redColor());
var image3:UIImage = UIImage(named: "pullto_3.png")!;
image3 = imageWithColor(image3, color: UIColor.redColor());
var image4:UIImage = UIImage(named: "pullto_4.png")!;
image4 = imageWithColor(image4, color: UIColor.redColor());
loaderS.animationImages = NSArray(objects: imageOne,
image2,
image3,
image4
);
loaderS.animationDuration = 1.4;
loaderS.animationRepeatCount = 99;
loaderS.startAnimating();
Here is a handy UIImage extension:
import UIKit
extension UIImage {
func imageWithTint(tint: UIColor) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, false, scale)
let context = UIGraphicsGetCurrentContext()
CGContextTranslateCTM(context, 0, size.height)
CGContextScaleCTM(context, 1.0, -1.0)
CGContextSetBlendMode(context, .Normal)
let rect = CGRect(origin: .zero, size: size)
CGContextClipToMask(context, rect, CGImage)
tint.setFill()
CGContextFillRect(context, rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image;
}
}
There's a rdar about this issue (http://www.openradar.me/23517334) and the problem still persists on iOS 11.
I adapted the code examples above to Swift 4.
extension UIImage {
func image(withTintColor color: UIColor) -> UIImage {
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(origin: .zero, size: size)
context?.clip(to: rect, mask: cgImage!)
color.setFill()
context?.fill(rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}
}
For Swift 5: Create image with color you want with below function. Then use those images to set to your image view's animation property:
extension UIImage {
func imageWithColor(_ color: UIColor) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale);
guard let context = UIGraphicsGetCurrentContext(), let cgImage = self.cgImage else { return nil }
context.translateBy(x: 0, y: self.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)
color.setFill()
context.fill(rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext();
return newImage
}
}
let animImages = [
image0.imageWithColor(color),
image1.imageWithColor(color),
image2.imageWithColor(color),
].compactMap({ $0 })
imageView.animationImages = animImages
imageView.animationDuration = 0.7
imageView.animationRepeatCount = 0
Here's updated code for Swift 4 with a few safety checks.
extension UIImage {
func image(withTint tint: UIColor) -> UIImage? {
guard let cgImage = cgImage else {
return nil
}
UIGraphicsBeginImageContextWithOptions(size, false, scale)
guard let context = UIGraphicsGetCurrentContext() else {
return nil
}
let rect = CGRect(origin: .zero, size: size)
context.translateBy(x: 0, y: size.height)
context.scaleBy(x: 1.0, y: -1.0)
context.setBlendMode(.normal)
context.clip(to: rect, mask: cgImage)
tint.setFill()
context.fill(rect)
let image = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return image
}
}
Maybe this example extension helps:
extension UIImageView {
func pulsingTintColor() {
UIView.animate(withDuration: 2, delay: 0.0, options: [.repeat, .autoreverse], animations: {
self.tintColor = UIColor.red
self.tintColor = UIColor.green
self.tintColor = UIColor.blue
}, completion: nil)
}
}
Ensure you have set the Render as: Template Image option in your asset catalog. This works for UIViews as well. Just replace tintColor with backgroundColor.
If you need parametrised colours:
func pulsingTintColor(with colors: [UIColor] = [UIColor.red, UIColor.green, UIColor.blue]) {
UIView.animate(withDuration: 2, delay: 0.0, options: [.repeat, .autoreverse], animations: {
colors.forEach({self.tintColor = $0})
}, completion: nil)
}

Resources