Changer la couleur du PNG dans les boutons - iOS


93

J'ai un ensemble d'icônes que j'ai créé qui sont des PNG blancs transparents:

entrez la description de l'image ici

Et ce que j'aimerais faire, c'est pouvoir les teinter avec d'autres couleurs. Tels que le bleu, le gris, etc.

J'ai remarqué que «cliqué / tapé», ils se transforment automatiquement en gris. Je suppose donc que je peux changer ce gris en ce que je veux avec un robinet ou son état normal:

entrez la description de l'image ici

Quelle serait la meilleure façon d'y parvenir?

Réponses:


225

Le code suivant définira la couleur de teinte pour l'état normal du bouton:

Pour Swift 4 et plus récent:

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

Vous pouvez changer la couleur de la teinte en fonction de vos besoins lorsque l'état du bouton change.


Versions plus anciennes

Pour Swift 3:

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

Pour Swift 2: voir l'historique des révisions.


Merveilleux! Mais comment revenir à l'image d'origine (non teintée)?
Marsman

@Marsman si vous regardez ma solution originaImage représente l'image originale et tintedImage représente la version teintée de l'image originale, donc vous ne remplacez pas l'image d'origine mais en créez une nouvelle version et vous aurez deux versions de la même image que vous pouvez utiliser comme par votre besoin
Yuvrajsinh

ne fonctionne pas sous iOS 11 avec xcode 9.1. Lorsque vous ajoutez la couleur de teinte, cela change complètement la couleur de l'imageView.
Vineesh TP

Les différentes modifications ont introduit des inexactitudes dans cette réponse.
Eric Aya

13

iOS 7 a introduit une propriété appelée tintColor pour les vues (y compris UIImageView). Cependant, vous devez également définir le type de rendu sur l'UIImage pour que cela ait un effet.

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

Cela devrait produire l'effet que vous recherchez dans un état par défaut.


10

Vous pouvez utiliser cette extension:

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

1
Cela ne fonctionne pas non plus pour moi. Lorsque j'utilise cette méthode, je ne vois que la couleur, pas l'image teintée de cette couleur.
Moebius

9

Pour changer la teinte de l'image ( choix , image classique , photo ), utilisez cela:

Exemple d'image: entrez la description de l'image ici entrez la description de l'image ici

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

}

pouvez-vous me dire comment utiliser ces méthodes signifie comment les appeler?
ashmi123

Cela ne fonctionne pas du tout pour moi. J'ai un PNG défini comme image du bouton. Lorsque j'utilise tintPhoto ou tintPicto, ils ne fonctionnent tout simplement pas.
Moebius

avez-vous ajouté votre image avecRenderingMode (.alwaysTemplate)? @Moebius
YannSteph

Oui, et lorsque j'utilise l'une des méthodes de teinte, tout ce que je vois est la couleur. J'ai même réglé l'alpha de la couleur à 0,5 et je ne vois toujours que la couleur. Swift 4
Moebius

Ok appliquer alpha après la teinte @Moebius
YannSteph

8

Si vous définissez l'image d'un bouton, accédez simplement à l'inspecteur d'attributs et changez le type de bouton en système. Ensuite, définissez l'image et changez la couleur de la teinte. La couleur de l'image changera. Si cela n'a pas eu lieu, vérifiez le type de bouton.


7

Swift 4 ou 5

extension UIButton{

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

}

Utilisation:

button.setImage(UIImage(named: "image_name"), for: .normal) // You can set image direct from Storyboard
button.setImageTintColor(UIColor.white)

il n'y a aucune méthode de setImageTintColor pour la vue UIbutton
Wahab Khan Jadon

C'est une extension d'UIButton. J'ai créé ci-dessus.
Krunal Patel le

6

Si vous utilisez des catalogues de ressources, vous pouvez définir la ressource image elle-même pour qu'elle s'affiche en mode modèle. Après cela, vous pouvez définir le tintColor du bouton dans Interface Builder (ou dans le code) et cela devrait prendre.


C'est la meilleure approche si vous utilisez la même image à plusieurs endroits car vous ne définissez l'image en mode modèle qu'une seule fois dans le catalogue de ressources.
Jonathan Cabrera

Cette approche n'a pas fonctionné pour moi. Lorsque je définis un PNG comme image de modèle, puis que je règle la couleur de teinte, l'image est remplacée par la couleur de teinte.
Moebius

C'est aussi la meilleure approche pour moi. Merci beaucoup. Simple facile réutilisable ...
Alparslan Selçuk Develioğlu

4

Swift 4

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

3

Si vous utilisez des catalogues de ressources, vous pouvez définir la ressource image elle-même pour qu'elle s'affiche en mode modèle. Après cela, vous pouvez définir le tintColor du bouton dans Interface Builder (ou dans le code) et cela devrait prendre.


1

J'ai trouvé l'approche la plus simple ci-dessous,

Ouvrez le catalogue d'actifs et sélectionnez l'image, puis accédez à l' inspecteur d'attributs et changez Render Asen Template Imagecomme ci-dessous

entrez la description de l'image ici

Ensuite, ajoutez le code ci-dessous dans le bouton Méthode d'action

yourButton.tintColor = .gray

-1

Swift 4 et 4.2

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

entrez la description de l'image ici

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.