UIButton图像颜色渐变

340
我注意到,当我将一个白色或黑色的UIImage放入一个UISegmentedControl中时,它会自动着色以匹配分段控件的色调。我觉得这很酷,并且想知道是否可以在其他地方也这样做。例如,我有一堆按钮,它们具有统一的形状但颜色不同。我能否通过使用这种颜色遮罩来为它们所有设置相同的图像,然后设置一种色调或其他东西来改变它们的实际颜色,而不是为每个按钮制作一个PNG文件呢?

你能否发布你想要使用的图片以及期望结果的图片? - Pratyusha Terli
这个做法与界面构建器中的操作相同。 - Chuy47
22个回答

704

从iOS 7开始,UIImage上有一个新的方法可以指定渲染模式。使用渲染模式UIImageRenderingModeAlwaysTemplate将允许按钮的色调控制图像颜色。

Objective-C

UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
UIImage *image = [[UIImage imageNamed:@"image_name"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[button setImage:image forState:UIControlStateNormal]; 
button.tintColor = [UIColor redColor];

快捷

let button = UIButton(type: .custom)
let image = UIImage(named: "image_name")?.withRenderingMode(.alwaysTemplate)
button.setImage(image, for: .normal)
button.tintColor = UIColor.red

20
我认为最好使用button.imageView.tintColor。 - M.Othman
4
只有在使用“button.tintColor”而不是“button.imageView.tintColor”时,@M.Othman的代码才对我起作用。 - pnizzle
35
请记得在xcassets中的图像上设置图像渲染模式,如@hashier所述。 - netwire
29
使用UIButtonTypeSystem类型创建一个按钮会自动采用您设置的tintColor。 - carloshwa
6
如果您的tintColor太暗,请确保adjustsImageWhenHighlighted为NO。(或在IB中:未选中“高亮时调整图像”) - Jason Moore
显示剩余3条评论

245

正如Ric在他的帖子中所提到的,你可以在代码中设置渲染模式,也可以直接在图像目录中进行设置,如下面附加的图像所示。只需将Render As设置为Template Image

输入图像描述

注意 我在iOS 7上使用这种方法时遇到了问题。因此,如果你也使用iOS 7,你可能想要在代码中进行设置以确保安全,可参考此处的描述。


1
顺便提一下,图像文件应该是黑色和透明的(不是黑白)。 - Axel Guilmin
6
不是这样的。您的图片可以是任何颜色并且可以是透明的。任何不透明的颜色将被转换为通用颜色,然后默认情况下会被加上黑色色调。 - Alejandro Iván

105

自定义按钮以其对应的图像颜色出现。在故事板中将按钮类型设置为“System”(或在代码中设置为UIButtonTypeSystem),将使用默认的色调渲染按钮的图像。

系统按钮类型渲染带色图标

(在iOS9,Xcode 7.3上测试通过)


2
可以通过使用此处建议的alwaysTemplate和tintColor方法来避免这种情况。.system按钮的优点是,您可以在轻触时改变颜色。 - Chris Prince

57

为了使tintColor影响UIImage,您必须将图像渲染模式设置为UIImageRenderingModeAlwaysTemplate。以下是Swift中的解决方案:

let image = UIImage(named: "image-name")
let button = UIButton()
button.setImage(image?.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate), forState: .Normal)
button.tintColor = UIColor.whiteColor()

SWIFT 4x

button.setImage(image.withRenderingMode(UIImage.RenderingMode.alwaysTemplate), for: .normal)
button.tintColor = UIColor.blue

37

如果您有一个带有背景图片的定制按钮,您可以设置按钮的色调颜色,并使用以下方法覆盖该图片。

在资源中选择要设置色调颜色的按钮背景。

在图像的属性检查器中,将“渲染为”值设置为“模板图像”。

输入图像描述

现在,每当您设置button.tintColor = UIColor.red时,您的按钮将以红色显示。


如果您在此处,可以前往以下链接:https://useyourloaf.com/blog/styling-buttons-using-the-asset-catalog/ ,然后滚动到模板图像(作为说明)。 - cspam
这是一个更好的解决方案,因为它减少了代码量,并且基本上做的事情与被接受的答案相同。 - DS.
我认为这应该是正确的。代码更少,易于处理。 - Umair_UAS

18
在Swift中,您可以这样做:
var exampleImage = UIImage(named: "ExampleImage.png")?.imageWithRenderingMode(.AlwaysTemplate)

然后在您的viewDidLoad方法中

exampleButtonOutlet.setImage(exampleImage, forState: UIControlState.Normal)

并且修改颜色

exampleButtonOutlet.tintColor = UIColor(red: 1, green: 0, blue: 0, alpha: 1) //your color

编辑 Xcode 8 现在您可以将图像在.xcassets中的渲染模式设置为“模板图像”,这样您就不需要再在var exampleImage 中专门声明它了。


14

我不确定你具体想要什么,但是这个类别方法可以使用指定的颜色遮盖UIImage,这样你就可以拥有一张单独的图片并将其颜色更改为任何你想要的颜色。

ImageUtils.h

- (UIImage *) maskWithColor:(UIColor *)color;

ImageUtils.m

-(UIImage *) maskWithColor:(UIColor *)color 
{
    CGImageRef maskImage = self.CGImage;
    CGFloat width = self.size.width;
    CGFloat height = self.size.height;
    CGRect bounds = CGRectMake(0,0,width,height);

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef bitmapContext = CGBitmapContextCreate(NULL, width, height, 8, 0, colorSpace, kCGImageAlphaPremultipliedLast);
    CGContextClipToMask(bitmapContext, bounds, maskImage);
    CGContextSetFillColorWithColor(bitmapContext, color.CGColor);    
    CGContextFillRect(bitmapContext, bounds);

    CGImageRef cImage = CGBitmapContextCreateImage(bitmapContext);
    UIImage *coloredImage = [UIImage imageWithCGImage:cImage];

    CGContextRelease(bitmapContext);
    CGColorSpaceRelease(colorSpace);
    CGImageRelease(cImage);

    return coloredImage;    
}

导入ImageUtils类别并执行以下操作...

#import "ImageUtils.h"

...

UIImage *icon = [UIImage imageNamed:ICON_IMAGE];

UIImage *redIcon = [icon maskWithColor:UIColor.redColor];
UIImage *blueIcon = [icon maskWithColor:UIColor.blueColor];

3
CGBitmapContextCreate中使用kCGBitmapAlphaInfoMask&kCGImageAlphaPremultipliedLast - Luis Ascorbe
4
不错,但需要进行调整以适配Retina图形... 当我在Retina图像上运行它时,它返回了一个非Retina的图像。 - jowie
为了支持Retina设备,您可以使用UIDevice类的比例属性:CGFloat scale = [UIScreen mainScreen].scale; CGFloat width = self.size.width * scale; CGFloat height = self.size.height * scale; scale属性从iOS 4.0开始存在。 - Philipp Frischmuth
在创建 UIImage 时,您还需要使用 scale 值:UIImage *coloredImage = [UIImage imageWithCGImage:cImage scale:scale orientation:self.imageOrientation]; - Philipp Frischmuth

8

使用Swift 4和自定义类型:

let button = UIButton(frame: aRectHere)
    let buttonImage = UIImage(named: "imageName")
    button.setImage(buttonImage?.withRenderingMode(.alwaysTemplate), for: .normal)
    button.tintColor = .white

7

Swift 3:

如果您已经通过xCode界面构建器设置了图像,则此解决方案可能很舒适。基本上,您有一个扩展来着色图像:

extension UIImage {
    public func image(withTintColor color: 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.normal)
        let rect: CGRect = CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height)
        context.clip(to: rect, mask: self.cgImage!)
        color.setFill()
        context.fill(rect)
        let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        return newImage
    }
}

接着,你可以准备这个UIButton扩展来为特定状态着色图像:

extension UIButton {
    func imageWith(color:UIColor, for: UIControlState) {
        if let imageForState = self.image(for: state) {
            self.image(for: .normal)?.withRenderingMode(.alwaysTemplate)
            let colorizedImage = imageForState.image(withTintColor: color)
            self.setImage(colorizedImage, for: state)
        }
    }
}

用法:

myButton.imageWith(.red, for: .normal)

P.S.(在表格单元格中也能正常工作,无需调用setNeedDisplay()方法,由于UIImage扩展,颜色的改变是即时的。)


6

对于 Xamarin.iOS (C#):

UIButton messagesButton = new UIButton(UIButtonType.Custom);
UIImage icon = UIImage.FromBundle("Images/icon.png");
messagesButton.SetImage(icon.ImageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate), UIControlState.Normal);
messagesButton.TintColor = UIColor.White;
messagesButton.Frame = new RectangleF(0, 0, 25, 25);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接