简体   繁体   English

如何在 iOS 和 WatchKit 中更改图像 tintColor

[英]How can I change image tintColor in iOS and WatchKit

I have an UIImageView called "theImageView", with UIImage in a single color (transparent background) just like the left black heart below.我有一个名为“theImageView”的 UIImageView,其中 UIImage 为单色(透明背景),就像下面的左黑心一样。 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?根据 iOS 7+ 导航栏图标中使用的色调方法,如何在 iOS 7 或更高版本中以编程方式更改此图像的色调颜色?

Can this method also work in WatchKit for an Apple Watch app?这种方法是否也适用于 Apple Watch 应用的 WatchKit?

在此处输入图片说明

iOS IOS
For an iOS app, in Swift 3, 4 or 5:对于 iOS 应用程序,在 Swift 3、4 或 5 中:

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

For Swift 2:对于 Swift 2:

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

Meanwhile, the modern Objective-C solution is:同时,现代的 Objective-C 解决方案是:

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 .在 Apple Watch 应用程序的 WatchKit 中,您可以为模板图像设置色调颜色

  1. 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.您必须将图像添加到 WatchKit 应用程序中的资产目录,并将图像集设置为在属性检查器中呈现为模板图像。 Unlike for an iPhone app, you cannot set the template rendering in code in the WatchKit Extension at present.与 iPhone 应用程序不同,目前您无法在 WatchKit 扩展中的代码中设置模板渲染。
  2. Set that image to be used in your WKInterfaceImage in interface builder for your app将该图像设置为在您的应用程序的界面构建器中的 WKInterfaceImage 中使用
  3. Create an IBOutlet in your WKInterfaceController for the WKInterfaceImage called 'theImage'...在 WKInterfaceController 中为名为“theImage”的 WKInterfaceImage 创建一个 IBOutlet...

To then set the tint color in Swift 3 or 4:然后在 Swift 3 或 4 中设置色调颜色:

theImage.setTintColor(UIColor.red)

Swift 2:斯威夫特 2:

theImage.setTintColor(UIColor.redColor())

To then set the tint color in Objective-C:然后在 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.如果您使用模板图像并且不应用色调颜色,则将应用 WatchKit 应用程序的全局色调。 If you have not set a Global Tint, theImage will be tinted light blue by default when used as a template image.如果你没有设置全局色调,当用作模板图像时,默认情况下图像会被theImage淡蓝色。

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 .我必须在 Swift 中使用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斯威夫特 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.更新视图中的色调颜色。

在视图中更新视图中的色调颜色

Swift 4斯威夫特 4

Change tint of UIImage SVG / PDF , that work for image with unique color :更改UIImage SVG / PDF 的色调,适用于具有独特颜色的图像

在此处输入图片说明 在此处输入图片说明

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 :更改UIImageView 的色调,适用于具有独特颜色的图像

在此处输入图片说明 在此处输入图片说明

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 :更改图片UIImage色调,使用它:

在此处输入图片说明 在此处输入图片说明

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

If anyone care a solution without UIImageView :如果有人关心没有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
    }
}

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快速 3 目的

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

Try this试试这个

http://robots.thoughtbot.com/designing-for-ios-blending-modes 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为 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)

Take benefit of Extension in Swift :-利用 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)

在此处输入图片说明

iOS IOS

Solution for doing it from Interface Builder, set templateImage param in keyPath and choose your tint color from IB从 Interface Builder 执行此操作的解决方案,在 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
    }
}

} }

With iOS 13 and above, you can simply use使用 iOS 13 及更高版本,您可以简单地使用

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

Swift 3 version of extension answer from fuzz来自fuzz 的Swift 3 版扩展答案

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
}

从 iOS 13 开始就有了 UIImage 的原生方法

let image = yourImage.withTintColor(.systemRed)

另外,对于上述答案,在 iOS 13 及更高版本中,有一种干净的方法

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

Swift 5斯威夫特 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:现在我使用这种基于 Duncan Babbage 响应的方法:

+ (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如果您有图像来替换清除按钮,则可以在 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
}

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

This is my UIImage extension and you can directly use changeTintColor function for an image.这是我的 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!
    }

}

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您可以使用更改changeColor函数来更改图像颜色

profileImageView.image = theImageView.image!.withRenderingMode(.alwaysTemplate) profileImageView.image = theImageView.image!.withRenderingMode(.alwaysTemplate)
profileImageView.tintColor = UIColor.green 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 profileImageView.tintColor = UIColor.green

if you have any id for the SVG image, you can fill the colours with respect to the ID.如果您有 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
        }
    }

}

OR Checkout this example.或查看此示例。

https://github.com/ravisfortune/SVGDEMO 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

Here's a simple extension that works for Swift 5:这是一个适用于 Swift 5 的简单扩展:

extension UIImageView {

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

Usage:用法:

myImageView.setImageTintColor(.systemBlue)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM