Cambiar el color de png en los botones - ios

93

Tengo un conjunto de iconos que he creado que son PNG transparentes en blanco:

ingrese la descripción de la imagen aquí

Y lo que me gustaría hacer es poder teñirlos de otros colores. Como azul, gris, etc.

He notado que "al hacer clic / tocar" cambian automáticamente a gris. Así que supongo que puedo cambiar ese gris a lo que quiera con un toque o en su estado normal:

ingrese la descripción de la imagen aquí

¿Cuál sería la mejor manera de lograrlo?

Galaxia
fuente

Respuestas:

225

El siguiente código establecerá el color del tinte para el estado normal del botón:

Para Swift 4 y versiones posteriores:

let origImage = UIImage(named: "imageName")
let tintedImage = origImage?.withRenderingMode(.alwaysTemplate)
btn.setImage(tintedImage, for: .normal)
btn.tintColor = .red

Puede cambiar el color del tinte según sus necesidades cuando el estado cambia para el botón.


versiones mas antiguas

Para Swift 3:

let origImage = UIImage(named: "imageName")
let tintedImage = origImage?.withRenderingMode(.alwaysTemplate)
btn.setImage(tintedImage, forState: .normal)
btn.tintColor = .redColor

Para Swift 2: consulte el historial de revisiones.

Yuvrajsinh
fuente
¡Maravilloso! Pero, ¿cómo se vuelve a la imagen original (sin teñir)?
Marsman
@Marsman, si miras mi solución, originaImage representa la imagen original y tintedImage representa la versión teñida de la imagen original, por lo que no estás reemplazando la imagen original, sino que estás creando una nueva versión y tendrás dos versiones de la misma imagen que puedes usar como según su necesidad
Yuvrajsinh
no funciona en iOS 11 con xcode 9.1. Cuando se agrega el color del tinte, se cambia completamente el color de imageView.
Vineesh TP
Las diversas ediciones han introducido inexactitudes en esta respuesta.
Eric Aya
13

iOS 7 introdujo una propiedad llamada tintColor para las vistas (incluido UIImageView). Sin embargo, también debe establecer el tipo de renderizado en UIImage para que esto tenga algún efecto.

UIImage *originalImage = [UIImage imageNamed:@"image.png"];
UIImage *tintedImage = [originalImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UIImageView *imageView = [[UIImageView alloc] initWithImage:tintedImage];

imageView.tintColor = [UIColor grayColor];
[self.view addSubview:imageView];

Esto debería producir el efecto que busca en un estado predeterminado.

JoGoFo
fuente
10

Puedes usar esta extensión:

import UIKit

extension CGContext {

    func fill(_ rect: CGRect,
              with mask: CGImage,
              using color: CGColor) {

        saveGState()
        defer { restoreGState() }

        translateBy(x: 0.0, y: rect.size.height)
        scaleBy(x: 1.0, y: -1.0)
        setBlendMode(.normal)

        clip(to: rect, mask: mask)

        setFillColor(color)
        fill(rect)
    }
}

extension UIImage {

    func filled(with color: UIColor) -> UIImage {
        let rect = CGRect(origin: .zero, size: self.size)
        guard let mask = self.cgImage else { return self }

        if #available(iOS 10.0, *) {
            let rendererFormat = UIGraphicsImageRendererFormat()
            rendererFormat.scale = self.scale

            let renderer = UIGraphicsImageRenderer(size: rect.size,
                                                   format: rendererFormat)
            return renderer.image { context in
                context.cgContext.fill(rect,
                                       with: mask,
                                       using: color.cgColor)
            }
        } else {
            UIGraphicsBeginImageContextWithOptions(rect.size,
                                                   false,
                                                   self.scale)
            defer { UIGraphicsEndImageContext() }

            guard let context = UIGraphicsGetCurrentContext() else { return self }

            context.fill(rect,
                         with: mask,
                         using: color.cgColor)
            return UIGraphicsGetImageFromCurrentImageContext() ?? self
        }
    }
}
Ilia Khalyapin
fuente
1
Esto tampoco me funciona. Cuando utilizo este método, todo lo que veo es el color, no la imagen teñida de ese color.
Moebius
9

Para cambiar el tinte de la imagen ( selección , imagen clásica , foto ) use eso:

Imagen de ejemplo: ingrese la descripción de la imagen aquí ingrese la descripción de la imagen aquí

Swift 2

public extension UIImage {
    /**
     Tint, Colorize image with given tint color<br><br>
     This is similar to Photoshop's "Color" layer blend mode<br><br>
     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<br><br>

     <img src="http://yannickstephan.com/easyhelper/tint1.png" height="70" width="120"/>

     **To**

     <img src="http://yannickstephan.com/easyhelper/tint2.png" height="70" width="120"/>

     - parameter tintColor: UIColor

     - returns: UIImage
     */
    public func tintPhoto(tintColor: UIColor) -> UIImage {

        return modifiedImage { context, rect in
            // draw black background - workaround to preserve color of partially transparent pixels
            CGContextSetBlendMode(context, .Normal)
            UIColor.blackColor().setFill()
            CGContextFillRect(context, rect)

            // draw original image
            CGContextSetBlendMode(context, .Normal)
            CGContextDrawImage(context, rect, self.CGImage)

            // tint image (loosing alpha) - the luminosity of the original image is preserved
            CGContextSetBlendMode(context, .Color)
            tintColor.setFill()
            CGContextFillRect(context, rect)

            // mask by alpha values of original image
            CGContextSetBlendMode(context, .DestinationIn)
            CGContextDrawImage(context, rect, self.CGImage)
        }
    }
    /**
     Tint Picto to color

     - parameter fillColor: UIColor

     - returns: UIImage
     */
    public func tintPicto(fillColor: UIColor) -> UIImage {

        return modifiedImage { context, rect in
            // draw tint color
            CGContextSetBlendMode(context, .Normal)
            fillColor.setFill()
            CGContextFillRect(context, rect)

            // mask by alpha values of original image
            CGContextSetBlendMode(context, .DestinationIn)
            CGContextDrawImage(context, rect, self.CGImage)
        }
    }
    /**
     Modified Image Context, apply modification on image

     - parameter draw: (CGContext, CGRect) -> ())

     - returns: UIImage
     */
    private func modifiedImage(@noescape draw: (CGContext, CGRect) -> ()) -> UIImage {

        // using scale correctly preserves retina images
        UIGraphicsBeginImageContextWithOptions(size, false, scale)
        let context: CGContext! = UIGraphicsGetCurrentContext()
        assert(context != nil)

        // correctly rotate image
        CGContextTranslateCTM(context, 0, size.height);
        CGContextScaleCTM(context, 1.0, -1.0);

        let rect = CGRectMake(0.0, 0.0, size.width, size.height)

        draw(context, rect)

        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
}

UPD

Swift 3

extension UIImage {

    /**
     Tint, Colorize image with given tint color<br><br>
     This is similar to Photoshop's "Color" layer blend mode<br><br>
     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<br><br>

     <img src="http://yannickstephan.com/easyhelper/tint1.png" height="70" width="120"/>

     **To**

     <img src="http://yannickstephan.com/easyhelper/tint2.png" height="70" width="120"/>

     - parameter tintColor: UIColor

     - returns: UIImage
     */
    func tintPhoto(_ tintColor: 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)
            tintColor.setFill()
            context.fill(rect)

            // mask by alpha values of original image
            context.setBlendMode(.destinationIn)
            context.draw(context.makeImage()!, in: rect)
        }
    }

    /**
     Tint Picto to color

     - parameter fillColor: UIColor

     - returns: UIImage
     */
    func tintPicto(_ fillColor: UIColor) -> UIImage {

        return modifiedImage { context, rect in
            // draw tint color
            context.setBlendMode(.normal)
            fillColor.setFill()
            context.fill(rect)

            // mask by alpha values of original image
            context.setBlendMode(.destinationIn)
            context.draw(cgImage!, 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!
    }

}
YannSteph
fuente
¿Puedes decirme cómo usar estos métodos? ¿Cómo llamarlos?
ashmi123
Esto no funciona en absoluto para mí. Tengo un PNG configurado como imagen del botón. Cuando utilizo tintPhoto o tintPicto, simplemente no funcionan.
Moebius
¿Agregaste tu imagen conRenderingMode (.alwaysTemplate)? @Moebius
YannSteph
Sí, y cuando utilizo cualquiera de los métodos de tinte, todo lo que veo es el color. Incluso configuré el alfa del color en 0.5 y todavía veo solo el color. Swift 4
Moebius
Ok, aplique alfa después del tinte @Moebius
YannSteph
8

Si está configurando la imagen para un botón, simplemente vaya al inspector de atributos y cambie el tipo de botón a sistema. Luego configure la imagen y cambie el color del tinte. El color de la imagen cambiará. Si no tuvo lugar, marque el tipo de botón.

Milligator
fuente
7

Rápido 4 o 5

extension UIButton{

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

}

Utilizar:

button.setImage(UIImage(named: "image_name"), for: .normal) // You can set image direct from Storyboard
button.setImageTintColor(UIColor.white)
Krunal Patel
fuente
no hay ningún método de setImageTintColor para la vista UIbutton
Wahab Khan Jadon
Es una extensión de UIButton. He creado arriba.
Krunal Patel
6

Si utiliza catálogos de activos, puede configurar el activo de imagen para que se represente en modo plantilla. Después de eso, puede configurar el tintColor del botón en Interface Builder (o en el código) y debería tomar.

moliveira
fuente
Este es el mejor enfoque si está utilizando la misma imagen en varios lugares, ya que solo configura la imagen en modo de plantilla una vez en el Catálogo de activos.
Jonathan Cabrera
Este enfoque no funcionó para mí. Cuando configuro un PNG como imagen de plantilla y luego configuro el color del tinte, la imagen se reemplaza por el color del tinte.
Moebius
Este es el mejor enfoque para mí también. Muchas gracias. Sencillo, fácil y reutilizable ...
Alparslan Selçuk Develioğlu
4

Rápido 4

    let origImage = UIImage(named: "check")
    let tintedImage = origImage?.withRenderingMode(.alwaysTemplate)
    buttons[0].setImage(tintedImage, for: .normal)
    buttons[0].tintColor = .red
Ahmed Safadi
fuente
3

Si utiliza catálogos de activos, puede configurar el activo de imagen para que se represente en modo plantilla. Después de eso, puede configurar el tintColor del botón en Interface Builder (o en el código) y debería tomar.

Ratnesh NS
fuente
1

Encontré el enfoque más fácil a continuación,

Abra assetcatalog y seleccione la imagen, luego vaya al inspector de atributos y cambie Render Asa Template Imagelo siguiente

ingrese la descripción de la imagen aquí

Luego agregue el código siguiente en el método de acción del botón

yourButton.tintColor = .gray
Kalpa
fuente
-1

Swift 4 y 4.2

let img = UIImage.init(named: "buttonName")?.withRenderingMode(UIImageRenderingMode.alwaysTemplate)
            btn.setImage(img, for: .normal)
            btn.tintColor = .gray

ingrese la descripción de la imagen aquí

Akbar Khan
fuente