我如何改变图像tintColor在iOS和WatchKit

我有一个名为theImageView的UIImageView, UIImage是单色的(透明背景),就像下面左边的黑色心形。我如何在iOS 7或更高的系统中,根据iOS 7+导航栏图标中使用的色调方法,以编程方式更改此图像的色调颜色?

这个方法也适用于WatchKit的Apple Watch应用程序吗?

enter image description here

292833 次浏览

这里有一个类别应该可以做到这一点

@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

所以你会这样做:

theImageView.image = [theImageView.image imageWithColor:[UIColor redColor]];

我必须在Swift中使用extension来做到这一点。

我想分享一下我是如何做到的:

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
}
}

用法:

theImageView.image = theImageView.image.imageWithColor(UIColor.redColor())

斯威夫特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!
}
}

用法:

theImageView.image = theImageView.image?.imageWithColor(color1: UIColor.red)

试试这个

http://robots.thoughtbot.com/designing-for-ios-blending-modes

- (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];
}
< p > iOS < br > 对于iOS应用,在Swift 3,4或5中:

theImageView.image = theImageView.image?.withRenderingMode(.alwaysTemplate)
theImageView.tintColor = UIColor.red

对于Swift 2:

theImageView.image = theImageView.image?.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
theImageView.tintColor = UIColor.redColor()

同时,现代的Objective-C解决方案是:

theImageView.image = [theImageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[theImageView setTintColor:[UIColor redColor]];

< p > Watchkit < br > 在Apple Watch应用程序的WatchKit中,你可以设置为模板图像着色。< / p >
  1. 您必须将图像添加到WatchKit应用程序中的资产目录,并将图像集设置为在属性检查器中呈现为模板图像。与iPhone应用程序不同,您目前不能在WatchKit扩展的代码中设置模板渲染。
  2. 设置该图像用于你的WKInterfaceImage在界面生成器为你的应用程序
  3. 创建一个IBOutlet在你的WKInterfaceController为WKInterfaceImage称为“theImage”…

然后在Swift 3或4中设置色调颜色:

theImage.setTintColor(UIColor.red)

斯威夫特2:

theImage.setTintColor(UIColor.redColor())

然后在Objective-C中设置色调颜色:

[self.theImage setTintColor:[UIColor redColor]];

如果您使用模板图像并且没有应用着色颜色,则将应用WatchKit应用程序的全局着色。如果你没有设置全局色调,theImage在用作模板图像时,默认会被染成浅蓝色。

与迅速

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

在故事板和图像资产中。你也可以改变这两个:

更新渲染模式为模板图像

在Image Assets中更新渲染模式为模板图像

更新视图中的色调颜色。

Update the tint Color in Views in Views

斯威夫特4

改变UIImage SVG / PDF的颜色,适用于色彩独特的图像:

enter image description here enter image description here < / p >

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
}
}

改变UIImageView的颜色,适用于色彩独特的图像:

enter image description here enter image description here < / p >

let imageView = UIImageView(frame: CGRect(x: 50, y: 50, width: 50, height: 50))
imageView.image = UIImage(named: "hello.png")!.withRenderingMode(.alwaysTemplate)
imageView.tintColor = .yellow

改变用户界面图像的颜色为图片,使用它:

enter image description here enter image description here < / p >

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!
}
}

现在我使用基于Duncan Babbage response的方法:

+ (UIImageView *) tintImageView: (UIImageView *)imageView withColor: (UIColor*) color{
imageView.image = [imageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[imageView setTintColor:color];
return imageView;
}

swift 3的目的

theImageView.image = theImageView.image!.withRenderingMode(.alwaysTemplate)
theImageView.tintColor = UIColor.red

你可以在Swift 3中使用它,如果你有一个图像来替换清除按钮

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
}

利用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)

enter image description here

如果有人关心没有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
}
}

子类,也可以从代码和接口生成器中使用:

@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

iOS

解决方案从接口生成器,在keyPath中设置templateImage参数和选择你的色调颜色从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
}
}

这是我的UIImage扩展,你可以直接使用changeTintColor函数的图像。

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!
}


}

示例用法如下

let image = UIImage(named: "sample_image")
imageView.image = image.changeTintColor(color: UIColor.red)

你可以使用change changeColor函数来改变图像的颜色

Swift 3版本的扩展答案从< em >模糊< / em >

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
}
< p > profileImageView。.withRenderingMode(.alwaysTemplate)
.image = theImageView.image profileImageView。tintColor = UIColor。绿色< / p >

首先在图像资产中选择特定图像,然后选择“模板”而不是“默认”,然后写一行。 profileImageView。tintColor = UIColor。绿色< / p >

用于着色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)

如果您有SVG图像的任何id,您可以根据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
}
}


}

或者签出这个例子。

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

在iOS 13及以上版本中,你可以简单地使用

let image = UIImage(named: "Heart")?.withRenderingMode(.alwaysTemplate)
if #available(iOS 13.0, *) {
imageView.image = image?.withTintColor(UIColor.white)
}

斯威夫特5

重绘图像的背景和填充颜色

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
}
}

自iOS 13以来,UIImage有一个原生方法

let image = yourImage.withTintColor(.systemRed)

另外,对于以上的答案,在iOS 13及以后有一个干净的方法

let image = UIImage(named: "imageName")?.withTintColor(.white, renderingMode: .alwaysTemplate)

这是一个简单的扩展,适用于Swift 5:

extension UIImageView {


func setImageTintColor(_ color: UIColor) {
let tintedImage = self.image?.withRenderingMode(.alwaysTemplate)
self.image = tintedImage
self.tintColor = color
}
}

用法:

myImageView.setImageTintColor(.systemBlue)