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

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


当前回答

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

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

其他回答

斯威夫特4

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

改变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

改变图片的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!
    }
}

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

@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]];

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

iOS 对于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]];

Watchkit 在Apple Watch应用程序的WatchKit中,您可以为模板图像设置色调颜色。

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

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

theImage.setTintColor(UIColor.red)

斯威夫特2:

theImage.setTintColor(UIColor.redColor())

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

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

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

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

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