Imagem de UIButton de tonalidade de cor

294

Percebi que quando coloco um branco ou preto UIImageem uma UISegmentedControlcor, ela automaticamente a mascara para corresponder à tonalidade do controle segmentado. Eu pensei que isso era muito legal, e queria saber se eu poderia fazer isso em outro lugar também. Por exemplo, eu tenho vários botões que têm uma forma uniforme, mas cores variadas. Em vez de criar um PNG para cada botão, eu poderia, de alguma forma, usar essa máscara de cores para usar a mesma imagem em todos eles, mas depois definir uma cor de tonalidade ou algo para alterar a cor real?

Logan Shire
fonte
Você pode postar a imagem que deseja usar e também a imagem para o resultado desejado?
Pratyusha Terli
Isso faz o mesmo do criador de interface stackoverflow.com/a/25179217/2051381 #
0000 Chuy47

Respostas:

619

No iOS 7, existe um novo método UIImagepara especificar o modo de renderização. O uso do modo de renderização UIImageRenderingModeAlwaysTemplatepermitirá que a cor da imagem seja controlada pela cor da tonalidade do botão.

Objetivo-C

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

Rápido

let button = UIButton(type: .custom)
let image = UIImage(named: "image_name")?.withRenderingMode(.alwaysTemplate)
button.setImage(image, for: .normal)
button.tintColor = UIColor.red
Ric Santos
fonte
14
Eu acho que é melhor usar o
button.imageView.tintColor
3
@ M.Othman só funciona para mim quando eu uso button.tintColor e não button.imageview.tintColor
pnizzle
32
Basta lembrar a imagem Jogo do modo de renderização na imagem em xcassets por @hashier
Dean
23
Criar um UIButton do tipo UIButtonTypeSystem respeitará automaticamente o tintColor que você definir.
precisa saber é o seguinte
4
Se o seu tintColorestiver muito escuro, verifique se adjustsImageWhenHighlightedNÃO. (Ou em IB: "Destaque ajusta a imagem" está desmarcada.)
Jason Moore
225

Como Ric já mencionou em seu post, você pode definir o modo de renderização no código, também pode fazer isso diretamente no catálogo de imagens, veja a imagem anexada abaixo. Basta definir o Render AsqueTemplate Image

insira a descrição da imagem aqui

Advertência Eu tive problemas com o iOS 7 e essa abordagem. Portanto, se você também usa o iOS 7, pode fazê-lo em código, para ter certeza, conforme descrito aqui .

hashier
fonte
1
Como uma nota lateral, o arquivo de imagem deve ser preto e transparente (não b & w)
Axel Guilmin
6
@AxelGuilmin não é verdade. Sua imagem pode ter qualquer cor desejada e transparente. Qualquer cor diferente de transparente será convertida em genérica e, em seguida, será pintada com a cor preta por padrão.
Alejandro Iván
90

Os botões personalizados aparecem em suas respectivas cores de imagem. Definir o tipo de botão como "Sistema" no storyboard (ou UIButtonTypeSystemno código) renderizará a imagem do botão com a cor padrão da tonalidade.

Tipo de botão Sistema renderiza ícones coloridos

(testado no iOS9, Xcode 7.3)

auco
fonte
2
O que pode ser evitado com os métodos alwaysTemplate e tintColor sugeridos aqui. Com a vantagem do botão .system, você obtém a mudança de cor com o toque na torneira.
Chris Prince
44

Você deve definir o modo de renderização da imagem UIImageRenderingModeAlwaysTemplatepara tintColorafetar a UIImage. Aqui está a solução no 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
Nick Wargnier
fonte
28

Se você tiver um botão personalizado com uma imagem de plano de fundo. Você pode definir a cor da tonalidade do seu botão e substituir a imagem pelas seguintes.

Nos ativos, selecione o plano de fundo do botão que você deseja definir na cor da tonalidade.

No inspetor de atributos da imagem, defina o valor renderizado como "Imagem do modelo"

insira a descrição da imagem aqui

Agora, sempre que você definir button.tintColor = UIColor.redo botão, será exibido em vermelho.

Ilker Baltaci
fonte
se você estiver aqui, acesse este link: useyourloaf.com/blog/styling-buttons-using-the-asset-catalog e vá até as imagens dos modelos (para servir de explicação)
cspam
Essa é uma solução melhor, pois reduz o código e praticamente faz a mesma coisa que a resposta aceita.
DS.
Eu acho que esse deve ser o correto. menos código e fácil de manusear.
Umair_UAS
17

No Swift, você pode fazer o seguinte:

var exampleImage = UIImage(named: "ExampleImage.png")?.imageWithRenderingMode(.AlwaysTemplate)

Então, na sua viewDidLoad

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

E para modificar a cor

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

EDIT Xcode 8 Agora você também pode apenas o modo de renderização da imagem em seus .xcassets para Template Image e, em seguida, não precisa declará-la especificamente var exampleImagemais

henrik-dmg
fonte
14

Não sabe exatamente o que deseja, mas esse método de categoria mascara uma UIImage com uma cor especificada, para que você possa ter uma única imagem e alterá-la para o que quiser.

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

Importe a categoria ImageUtils e faça algo assim ...

#import "ImageUtils.h"

...

UIImage *icon = [UIImage imageNamed:ICON_IMAGE];

UIImage *redIcon = [icon maskWithColor:UIColor.redColor];
UIImage *blueIcon = [icon maskWithColor:UIColor.blueColor];
Kirby Todd
fonte
3
Use kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedLastonCGBitmapContextCreate
Luis Ascorbe
4
Bom, mas precisa ser ajustado para os gráficos Retina ... Quando executo isso em uma imagem Retina, ela retorna uma que não é retina.
jowie
Para oferecer suporte a dispositivos Retina, você pode usar a propriedade scale da UIDeviceclasse: CGFloat scale = [UIScreen mainScreen].scale; CGFloat width = self.size.width * scale; CGFloat height = self.size.height * scale;A scalepropriedade existe no iOS 4.0.
Philipp Frischmuth
Você também precisa usar o scalevalor quando ele UIImageé criado:UIImage *coloredImage = [UIImage imageWithCGImage:cImage scale:scale orientation:self.imageOrientation];
Philipp Frischmuth
8

Swift 4 com customType:

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

Para 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);
Maciej
fonte
5

Swift 3 :

Essa solução pode ser confortável se você já configurou sua imagem através do construtor de interface xCode. Basicamente, você tem uma extensão para colorir uma imagem:

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

Em seguida, você pode preparar esta extensão UIButton para colorir a imagem para um estado específico:

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

Uso:

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

PS (funcionando bem também nas células da tabela, você não precisa chamar o setNeedDisplay()método, a alteração da cor é imediata devido à extensão UIImage .

Alessandro Ornano
fonte
3

Se você deseja mascarar manualmente sua imagem, aqui está um código atualizado que funciona com telas retina

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

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

    CGImageRef cImage = CGBitmapContextCreateImage(bitmapContext);
    UIImage *coloredImage = [UIImage imageWithCGImage:cImage scale:self.scale orientation:self.imageOrientation];

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

    return coloredImage;
}
Josh Bernfeld
fonte
2

Você deveria tentar

Depois de definir o quadro

NSArray *arr10 =[NSArray arrayWithObjects:btn1,btn2,nil];
for(UIButton *btn10 in arr10)
{
CAGradientLayer *btnGradient2 = [CAGradientLayer layer];
btnGradient2.frame = btn10.bounds;

btnGradient2.colors = [NSArray arrayWithObjects:
                       (id)[[UIColor colorWithRed:151.0/255.0f green:206.0/255.5 blue:99.0/255.0 alpha:1] CGColor],
                       (id)[[UIColor colorWithRed:126.0/255.0f green:192.0/255.5 blue:65.0/255.0 alpha:1]CGColor],
                       nil];
[btn10.layer insertSublayer:btnGradient2 atIndex:0];

}
guptha
fonte
2

Swift 3.0

    let image = UIImage(named:"NoConnection")!

 warningButton = UIButton(type: .system)        
    warningButton.setImage(image, for: .normal)
    warningButton.tintColor = UIColor.lightText
    warningButton.frame = CGRect(origin: CGPoint(x:-100,y:0), size: CGSize(width: 59, height: 56))

    self.addSubview(warningButton)
Jad
fonte
1

Alterar a imagem do botão ou a cor da tonalidade da visualização da imagem Swift:

btn.imageView?.image = btn.imageView?.image?.withRenderingMode(.alwaysTemplate)

btn.imageView?.tintColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
Urvish Modi
fonte
-1

Nenhuma das opções acima funcionou para mim, porque a tonalidade foi limpa após o clique. Eu tive que usar

button.setImageTintColor(Palette.darkGray(), for: UIControlState())
Szymon Klimaszewski
fonte