Come posso cambiare l'immagine tintColor in iOS e WatchKit


395

Ho un UIImageView chiamato "theImageView", con UIImage in un unico colore (sfondo trasparente) proprio come il cuore nero sinistro in basso. Come posso cambiare il colore della tinta di questa immagine a livello di codice in iOS 7 o versioni successive, secondo il metodo di tinta usato nelle icone della barra di navigazione di iOS 7+?

Questo metodo può funzionare anche in WatchKit per un'app Apple Watch?

inserisci qui la descrizione dell'immagine


4
Cosa intendi con "il seguente codice è sbagliato", impostando a UIImagewith UIImageRenderingModeAlwaysTemplatee poi settando UIImageVIewil tintColorDOES funziona. (nel mio codice ^^)
Vinzzz,

2
Usa un png con trasparenza come questo
Alladiniano

4
Dovresti davvero spostare la tua risposta nella sezione delle risposte, poiché penso che sia la migliore e la più moderna.
Richard Venable,

Vorrei poter raddoppiare questa domanda !!
Jacobo Koenig,

Risposte:


764

iOS
Per un'app iOS, in Swift 3, 4 o 5:

theImageView.image = theImageView.image?.withRenderingMode(.alwaysTemplate)
theImageView.tintColor = UIColor.red

Per Swift 2:

theImageView.image = theImageView.image?.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
theImageView.tintColor = UIColor.redColor()

Nel frattempo, la moderna soluzione Objective-C è:

theImageView.image = [theImageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[theImageView setTintColor:[UIColor redColor]];

Watchkit
Nelle app WatchKit per Apple Watch, puoi impostare il colore della tinta per un'immagine modello .

  1. È necessario aggiungere la propria immagine a un catalogo delle risorse nell'app WatchKit e impostare il set di immagini da renderizzare come immagine modello nella finestra di ispezione degli attributi. A differenza di un'app per iPhone, al momento non è possibile impostare il rendering del modello in codice nell'estensione WatchKit.
  2. Imposta l'immagine da utilizzare in WKInterfaceImage nel generatore di interfacce per la tua app
  3. Crea un IBOutlet nel tuo WKInterfaceController per WKInterfaceImage chiamato 'theImage' ...

Per impostare il colore della tinta in Swift 3 o 4:

theImage.setTintColor(UIColor.red)

Swift 2:

theImage.setTintColor(UIColor.redColor())

Per impostare il colore della tinta in Objective-C:

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

Se usi un'immagine modello e non applichi un colore di tinta, verrà applicata la Tinta globale per l'app WatchKit. Se non hai impostato una Tinta globale, theImageper impostazione predefinita sarà colorata di blu chiaro quando utilizzata come immagine modello.


2
questa è la soluzione migliore e semplice.
Ankish Jain,

4
imageWithRenderingMode è troppo lento. Nello storyboard e nelle risorse immagine. puoi anche cambiare questi due: Aggiorna la Modalità rendering in Immagine modello - questa è una soluzione migliore
Katerina,

Perfetto, ora uso questo metodo basato sul codice: + (UIImageView ) tintImageView: (UIImageView *) imageView withColor: (UIColor ) color {imageView.image = [imageView.image imageWithRenderingMode: UIImageRenderingModeAlwaysTemplate]; [imageView setTintColor: color]; restituire imageView; }
Josep Escobar,

è meglio con l'immagine nera?
Bruno,

1
L'immagine di Bruno non deve essere nera, no. Funziona con qualsiasi colore.
Duncan Babbage,

121

Ecco una categoria che dovrebbe fare il trucco

@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

quindi faresti:

theImageView.image = [theImageView.image imageWithColor:[UIColor redColor]];

Grazie per questa risposta molto valida, immagino che il mio codice fosse ok dall'inizio, dovrei rispondere alla mia domanda e ti ho dato un +1 a prescindere ..
gommoso

104

Ho dovuto farlo in Swift usando un extension.

Ho pensato di condividere come ho fatto:

extension UIImage {
    func imageWithColor(color1: UIColor) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
        color1.setFill()

        let context = UIGraphicsGetCurrentContext() as CGContextRef
        CGContextTranslateCTM(context, 0, self.size.height)
        CGContextScaleCTM(context, 1.0, -1.0);
        CGContextSetBlendMode(context, CGBlendMode.Normal)

        let rect = CGRectMake(0, 0, self.size.width, self.size.height) as CGRect
        CGContextClipToMask(context, rect, self.CGImage)
        CGContextFillRect(context, rect)

        let newImage = UIGraphicsGetImageFromCurrentImageContext() as UIImage
        UIGraphicsEndImageContext()

        return newImage
    }
}

Uso:

theImageView.image = theImageView.image.imageWithColor(UIColor.redColor())

Swift 4

extension UIImage {
    func imageWithColor(color1: UIColor) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
        color1.setFill()

        let context = UIGraphicsGetCurrentContext()
        context?.translateBy(x: 0, y: self.size.height)
        context?.scaleBy(x: 1.0, y: -1.0)
        context?.setBlendMode(CGBlendMode.normal)

        let rect = CGRect(origin: .zero, size: CGSize(width: self.size.width, height: self.size.height))
        context?.clip(to: rect, mask: self.cgImage!)
        context?.fill(rect)

        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return newImage!
    }
}

Uso:

theImageView.image = theImageView.image?.imageWithColor(color1: UIColor.red)


1
Cordiali saluti, questo non ha funzionato per me finché non ho spostato la color1.setFill()destra sotto la prima riga del metodo UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale).
Aaron,

@Aaron Aggiornato in base al tuo commento. Grazie.
Fulvio,

7
@CeceXX usa CGBlendMode.Normalinvece
Adolfo

2
Sei fantastico, tuttavia potresti
doverlo

1
@SimpiMind Ha fornito invece Swift 4.
Fulvio,

97

Nello storyboard e nelle risorse immagine. puoi cambiare anche questi due:

Aggiorna la modalità di rendering all'immagine modello

Aggiorna la modalità di rendering all'immagine modello nelle risorse immagine

Aggiorna il colore della tinta in Viste.

Aggiorna il colore della tinta in Viste in Viste


22
Questa è davvero la risposta più tosta!
brandonscript

1
L'impostazione di questo valore dallo storyboard non funziona mai per me. Devo sempre usare imageView.tintColordal codice.
Kamil Powałowski il

3
@ KamilPowałowski per me questo funziona a volte ... Non sono sicuro del perché. Vorrei sapere perché non sempre funziona. Quindi finisco per farlo con il codice
Jesus Rodriguez,

2
Per me, questo metodo storyboard funziona su pulsanti ma non su ImageViews. Devo ancora impostare tintColor nel codice per imageViews.
Derek Soike,

2
Nel caso in cui qualcuno si stia ancora grattando la testa chiedendosi perché non funziona in IB, prova a impostare l'immagine di Opaque su No.
Bonan,

40

Swift 4

Cambia la tinta di UIImage SVG / PDF , che funziona per immagini con colori unici :

inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine

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

Cambia la tinta di UIImageView , che funziona per immagini con colori unici :

inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine

let imageView = UIImageView(frame: CGRect(x: 50, y: 50, width: 50, height: 50))
imageView.image = UIImage(named: "hello.png")!.withRenderingMode(.alwaysTemplate)
imageView.tintColor = .yellow

Cambia la tinta di UIImage per l' immagine , usa questo:

inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine

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

1
ehi, sono nuovo in fretta, ma qui hai detto che è per le immagini SVG, ma non riesco a trovare un modo per analizzare l'SVG in UIImage, potresti aiutarmi? o forse in qualche modo posso gestirlo correttamente con SVG. Grazie!
Dumitru Rogojinaru,

@DumitruRogojinaru usa la funzione SVG con l'immagine modello nell'asset
YannSteph

Perché è necessario tradurre e ridimensionare su "immagine modificata"?
Luca Davanzo,

Aggiornamento per Swift 4
YannSteph,

36

Se a qualcuno interessa una soluzione senza 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
    }
}

Wow, funziona come per magia dopo averlo cercato per un'ora +. Necessario per: impostare un'icona in un NSTextAttachment in un colore diverso da quello originale dell'icona. La risposta standard per utilizzare UIImageView e modificarne il colore non funziona qui, perché NSTextAttachment non utilizza UIImageView.
marco,

1
Questa è la migliore soluzione che ho trovato finora soprattutto per chiunque sia alla ricerca di codice che funzioni con Swift 3. Ottimo suggerimento!
Shashwat,

17

Con Swift

let commentImageView = UIImageView(frame: CGRectMake(100, 100, 100, 100))
commentImageView.image = UIImage(named: "myimage.png")!.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
commentImageView.tintColor = UIColor.blackColor()
addSubview(commentImageView)

3
puoi semplicemente mettere .AlwaysTemplate.
Rui Peres,

sì, accorcia il codice, ma sembra che potrebbe ridurre la chiarezza del codice. non sono sicuro delle scorciatoie da punti a causa di ciò
Esqarrouth,

Vedo il tuo POV, solo un'alternativa.
Rui Peres,

4

Prova questo

http://robots.thoughtbot.com/designing-for-ios-blending-modes

o

- (void)viewDidLoad
{
[super viewDidLoad];

UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 30, 300, 50)];
label.numberOfLines = 0;
label.font = [UIFont systemFontOfSize:13];
label.text = @"These checkmarks use the same gray checkmark image with a tintColor applied to the image view";
[self.view addSubview:label];

[self _createImageViewAtY:100 color:[UIColor purpleColor]];
}

- (void)_createImageViewAtY:(int)y color:(UIColor *)color {
UIImage *image = [[UIImage imageNamed:@"gray checkmark.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
CGRect frame = imageView.frame;
frame.origin.x = 100;
frame.origin.y = y;
imageView.frame = frame;

if (color)
    imageView.tintColor = color;

[self.view addSubview:imageView];
}

4

Per 3 rapidi scopi

theImageView.image = theImageView.image!.withRenderingMode(.alwaysTemplate) theImageView.tintColor = UIColor.red


2

Per colorare l'immagine di un UIButton

let image1 = "ic_shopping_cart_empty"
btn_Basket.setImage(UIImage(named: image1)?.withRenderingMode(.alwaysTemplate), for: .normal)
btn_Basket.setImage(UIImage(named: image1)?.withRenderingMode(.alwaysTemplate), for: .selected)
btn_Basket.imageView?.tintColor = UIColor(UIColor.Red)

2

iOS

Soluzione per farlo da Interface Builder, impostare templateImage param in keyPath e scegliere il colore della tinta da IB

extension UIImageView {

// make template image with tint color
var templateImage: Bool {
    set {
        if newValue, let image = self.image {
            let newImage = image.withRenderingMode(.alwaysTemplate)
            self.image = newImage
        }
    } get {
        return false
    }
}

}


2

Con iOS 13 e versioni successive, puoi semplicemente utilizzare

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

1

Approfitta dell'estensione in Swift: -

extension UIImageView {
    func changeImageColor( color:UIColor) -> UIImage
    {
        image = image!.withRenderingMode(.alwaysTemplate)
        tintColor = color
        return image!
    }
}

   //Change color of logo 
   logoImage.image =  logoImage.changeImageColor(color: .red)

inserisci qui la descrizione dell'immagine


1

Swift 3 versione dell'estensione risposta da fuzz

func imageWithColor(color: UIColor) -> UIImage {
    UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
    color.setFill()

    let context = UIGraphicsGetCurrentContext()! as CGContext
    context.translateBy(x: 0, y: self.size.height)
    context.scaleBy(x: 1.0, y: -1.0);
    context.setBlendMode(.normal)

    let rect = CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height) as CGRect
    context.clip(to: rect, mask: self.cgImage!)
    context.fill(rect)

    let newImage = UIGraphicsGetImageFromCurrentImageContext()! as UIImage
    UIGraphicsEndImageContext()

    return newImage
}

0

Ora utilizzo questo metodo basato sulla risposta Duncan Babbage:

+ (UIImageView *) tintImageView: (UIImageView *)imageView withColor: (UIColor*) color{
    imageView.image = [imageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
    [imageView setTintColor:color];
    return imageView;
}

0

Puoi usarlo in Swift 3 se hai un'immagine per sostituire il pulsante Cancella

func addTextfieldRightView(){

    let rightViewWidth:CGFloat = 30

    let viewMax = self.searchTxt.frame.height
    let buttonMax = self.searchTxt.frame.height - 16

    let buttonView = UIView(frame: CGRect(
        x: self.searchTxt.frame.width - rightViewWidth,
        y: 0,
        width: viewMax,
        height: viewMax))

    let myButton = UIButton(frame: CGRect(
        x: (viewMax - buttonMax) / 2,
        y: (viewMax - buttonMax) / 2,
        width: buttonMax,
        height: buttonMax))

    myButton.setImage(UIImage(named: "BlueClear")!, for: .normal)

    buttonView.addSubview(myButton)

    let clearPressed = UITapGestureRecognizer(target: self, action: #selector(SearchVC.clearPressed(sender:)))
    buttonView.isUserInteractionEnabled = true
    buttonView.addGestureRecognizer(clearPressed)

    myButton.addTarget(self, action: #selector(SearchVC.clearPressed(sender:)), for: .touchUpInside)

    self.searchTxt.rightView = buttonView
    self.searchTxt.rightViewMode = .whileEditing
}

0

Sottoclasse che può essere utilizzata anche da Code e Interface Builder:

@implementation TintedImageView

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        [self setup];
    }
    return self;
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
        [self setup];
    }
    return self;
}

-(void)setup {
    self.image = [self.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
}

@end

0

Questa è la mia estensione UIImage e puoi usare direttamente la funzione changeTintColor per un'immagine.

extension UIImage {

    func changeTintColor(color: UIColor) -> UIImage {
        var newImage = self.withRenderingMode(.alwaysTemplate)
        UIGraphicsBeginImageContextWithOptions(self.size, false, newImage.scale)
        color.set()
        newImage.draw(in: CGRect(x: 0.0, y: 0.0, width: self.size.width, height: self.size.height))
        newImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        return newImage
    }

    func changeColor(color: UIColor) -> UIImage {
        let backgroundSize = self.size
        UIGraphicsBeginImageContext(backgroundSize)
        guard let context = UIGraphicsGetCurrentContext() else {
            return self
        }
        var backgroundRect = CGRect()
        backgroundRect.size = backgroundSize
        backgroundRect.origin.x = 0
        backgroundRect.origin.y = 0

        var red: CGFloat = 0
        var green: CGFloat = 0
        var blue: CGFloat = 0
        var alpha: CGFloat = 0
        color.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
        context.setFillColor(red: red, green: green, blue: blue, alpha: alpha)
        context.translateBy(x: 0, y: backgroundSize.height)
        context.scaleBy(x: 1.0, y: -1.0)
        context.clip(to: CGRect(x: 0.0, y: 0.0, width: self.size.width, height: self.size.height),
                 mask: self.cgImage!)
        context.fill(backgroundRect)

        var imageRect = CGRect()
        imageRect.size = self.size
        imageRect.origin.x = (backgroundSize.width - self.size.width) / 2
        imageRect.origin.y = (backgroundSize.height - self.size.height) / 2

        context.setBlendMode(.multiply)
        context.draw(self.cgImage!, in: imageRect)

        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage!
    }

}

Esempio di utilizzo come questo

let image = UIImage(named: "sample_image")
imageView.image = image.changeTintColor(color: UIColor.red)

E puoi usare la changeColorfunzione cambia per cambiare il colore dell'immagine


0

profileImageView.image = theImageView.image! .withRenderingMode (.alwaysTemplate)
profileImageView.tintColor = UIColor.green

O

Prima seleziona Immagine particolare nella risorsa immagine, quindi seleziona arrossata come Modello anziché Predefinito e dopo quella riga di scrittura. profileImageView.tintColor = UIColor.green


0

se si dispone di un ID per l'immagine SVG, è possibile riempire i colori rispetto all'ID.

    let image = SVGKImage(named: "iconName")
    let svgIMGV = SVGKFastImageView(frame: self.imgView.frame)
         svgIMGV.image = image
          svgIMGV.fillTintColor(colorImage: UIColor.red, iconID: "Bank")
// Add in extension SVGKImageView
extension SVGKImageView {
 func fillTintColor(colorImage: UIColor, iconID: String) {
        if self.image != nil && self.image.caLayerTree != nil {
            print(self.image.caLayerTree.sublayers)
            guard let sublayers = self.image.caLayerTree.sublayers else { return }
            fillRecursively(sublayers: sublayers, color: colorImage, iconID: iconID)
        }
    }

     private func fillRecursively(sublayers: [CALayer], color: UIColor, iconID: String, hasFoundLayer: Bool) {
        var isLayerFound = false
        for layer in sublayers {
            if let l = layer as? CAShapeLayer {

                print(l.name)                
                //IF you want to color the specific shapelayer by id else remove the l.name  == "myID"  validation
                if let name =  l.name,  hasFoundLayer == true && name == "myID" {
                    self.colorThatImageWIthColor(color: color, layer: l)
                    print("Colouring FInished")
                }
            } else {
                if layer.name == iconID {
                    if let innerSublayer = layer.sublayers as? [CAShapeLayer] {
                        fillRecursively(sublayers: innerSublayer, color: color, iconID: iconID, hasFoundLayer: true )
                        print("FOund")
                    }
                } else {
                    if let l = layer as? CALayer, let sub = l.sublayers {
                        fillRecursively(sublayers: sub, color: color, iconID: iconID, hasFoundLayer: false)
                    }
                }
            }

        }
    }

    func colorThatImageWIthColor(color: UIColor, layer: CAShapeLayer) {
        if layer.strokeColor != nil {
            layer.strokeColor = color.cgColor
        }
        if layer.fillColor != nil {
            layer.fillColor = color.cgColor
        }
    }

}

OPPURE Dai un'occhiata a questo esempio.

https://github.com/ravisfortune/SVGDEMO


0
let navHeight = self.navigationController?.navigationBar.frame.height;
let menuBtn = UIButton(type: .custom)
menuBtn.frame = CGRect(x: 0, y: 0, width: 45, height: navHeight!)     
menuBtn.setImage(UIImage(named:"image_name")!.withRenderingMode(.alwaysTemplate), for: .normal)        
menuBtn.tintColor = .black
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.