Ändern Sie den UIImage-Rendering-Modus aus einer Storyboard- / XIB-Datei

93

Ist es möglich, a UIImage's renderingModeüber ein Storyboard oder einen xib-Editor zu ändern ?

Ziel ist es, tintColorauf das jeweilige UIImageViewObjekt anzuwenden .

Artem Stepanenko
quelle

Antworten:

101

So können Sie dies in .xib- oder Storyboard-Dateien tun:

(Obj-C) Erstellen Sie eine Kategorie für UIImageView:

@interface UIImageView (Utils)

- (void)setImageRenderingMode:(UIImageRenderingMode)renderMode;

@end

@implementation UIImageView (Utils)

- (void)setImageRenderingMode:(UIImageRenderingMode)renderMode
{
    NSAssert(self.image, @"Image must be set before setting rendering mode");
    self.image = [self.image imageWithRenderingMode:renderMode];
}

@end

(Swift 4) Erstellen Sie eine Erweiterung für UIImageView:

extension UIImageView {
    func setImageRenderingMode(_ renderMode: UIImage.RenderingMode) {
        assert(image != nil, "Image must be set before setting rendering mode")
        // AlwaysOriginal as an example
        image = image?.withRenderingMode(.alwaysOriginal)
    }
}

Fügen Sie dann im Identitätsinspektor in der xib-Datei ein Laufzeitattribut hinzu:

Geben Sie hier die Bildbeschreibung ein

Schneemann
quelle
44
Was ich an dieser Antwort liebe, ist, dass sie eine Antwort auf die Frage ist.
Algen
1
Ich würde es vorziehen, eine UIImageView-Unterklasse zu erstellen, anstatt die Schlüsselwerteinstellung vorzunehmen. Weil dies einfacher einzurichten ist und wir die Nummerneinstellung auf den Aufzählungswert vermeiden könnten. Zum Beispiel: `@implementation TemplateRenderingImageView - (id) initWithCoder: (NSCoder *) aDecoder {self = [super initWithCoder: aDecoder]; if (self) {self.image = [self.image imageWithRenderingMode: UIImageRenderingModeAlwaysTemplate]; } return self; } @ end`
John Fantasy
1
Gute Antwort! Die Screenshots waren hilfreich.
BigSauce
1
Funktioniert natürlich nicht mit Launch Screen.xib, da Sie keine benutzerdefinierten Laufzeitattribute verwenden können.
Steve Moser
3
Hardcoding 2 als Wert ist schlecht schlecht schlecht .. Die Verwendung des xcassets-Katalogs ist die richtige Antwort.
Gilani
198

Sie können den Bildwiedergabemodus nicht in der .xibDatei, sondern in einer .xcassetsBibliothek einstellen .

Wählen Sie nach dem Hinzufügen eines Bildes zu einer Asset-Bibliothek das Bild aus und öffnen Sie den Attributinspektor auf der rechten Seite von Xcode. Suchen Sie das Attribut 'Rendern als' und setzen Sie es auf 'Vorlage'.

Nachdem Sie den Rendering-Modus eines Bildes festgelegt haben, können Sie der Datei UIImageViewin a .xiboder eine Farbtonfarbe hinzufügen .storyboard, um die Bildfarbe anzupassen.

Dadurch wird die Eigenschaft für das Image überall dort festgelegt, wo sie verwendet wird, und nicht nur in einer Interface Builder-Datei. In fast allen Fällen (auf die ich gestoßen bin) ist dies jedoch das gewünschte Verhalten.

Screenshot von Xcode mit dem Attributinspektor für ein Bild

Ein paar Dinge zu beachten:

  • Die Bildfarbe scheint sich im Interface Builder (ab Xcode 6.1.1) nicht geändert zu haben, funktioniert jedoch, wenn die Anwendung ausgeführt wird.
  • Ich habe einige Fehler mit dieser Funktion festgestellt und in einigen Situationen musste ich die entfernen und erneut hinzufügen UIImageView. Ich habe das nicht tief untersucht.
  • Dies funktioniert auch hervorragend bei anderen UIKitComponentswie Bildern in UIButton's und UIBarButtonItem' s.
  • Wenn Ihre Asset-Bibliothek eine Reihe von weißen Bildern enthält, die nicht sichtbar sind, können Sie Ihr Leben um das 10-fache verbessern, indem Sie sie schwarz / transparent machen und den Rendering-Modus ändern.
Anthony Mattox
quelle
15
Es scheint einen Fehler mit aktivierter Farbtonfarbe zu geben UIImageView, sodass die Farbtonfarbe beim Ausführen der App nicht immer angezeigt wird.
Nebel
@Fogh Ich hatte auch solche inkonsistenten Fehler. Behebt dies programmgesteuert das Einstellen der Farbtonfarbe?
Anthony Mattox
2
Ich kann bestätigen, dass beim Einstellen der Farbtonfarbe in IB ein Problem vorliegt. Das programmgesteuerte Einstellen funktioniert. Ich habe einen Fehler # 20305518 dafür eingereicht.
Nikolay Derkach
1
@ AxelGuilmin Yup. Eigentlich wird nur der Alphakanal verwendet, es kann also jede Farbe sein, solange die Transparenz Ihren Wünschen entspricht.
Anthony Mattox
1
Es funktioniert jetzt mit Xcode 7.3 (7D175)! Obwohl die akzeptierte Antwort eine sehr intuitive Problemumgehung ist, bevorzuge ich stattdessen diese Antwort.
Nstein
43

Die Verwendung des Vorlagen-Rendering-Modus mit einem UIImageView in einem Storyboard oder xib ist sowohl unter iOS 7 als auch unter iOS 8 sehr fehlerhaft.

Unter iOS 7

Das UIImage wird vom Storyboard / xib nicht richtig dekodiert. Wenn Sie die imageView.image.renderingModeEigenschaft in der viewDidLoadMethode überprüfen , werden Sie feststellen, dass dies immer der Fall ist UIImageRenderingModeAutomatic, auch wenn Sie sie in Ihrer xcassets-Datei auf Als Vorlagenbild rendern festlegen.

Um dies zu umgehen, müssen Sie den Rendering-Modus manuell einstellen:

self.imageView.image = [self.imageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];

Unter iOS 8

Das UIImage wird ordnungsgemäß dekodiert und seine renderingModeEigenschaft spiegelt wider, was in der xcassets-Datei ausgewählt wurde, aber das Bild ist nicht getönt.

Um dies zu umgehen, haben Sie zwei Möglichkeiten:

  1. Legen Sie die tintColorEigenschaft im benutzerdefinierten Laufzeitattribut anstelle des Inspektorbereichs "Attribute" fest.

oder

  1. Setzen Sie die tintColor manuell zurück:
UIColor *tintColor = self.imageView.tintColor;
self.imageView.tintColor = nil;
self.imageView.tintColor = tintColor;

Sie können Ihre bevorzugte Option auswählen, wobei beide das Bild richtig tönen.

(Wenn Sie mit Xcode 6.2 kompilieren, self.imageView.tintColor = self.imageView.tintColor;reicht es aus, dies nur zu tun , aber dies funktioniert nicht mehr, wenn Sie mit Xcode 6.3 kompilieren.)

Fazit

Wenn Sie sowohl iOS 7 als auch iOS 8 unterstützen müssen, benötigen Sie beide Problemumgehungen. Wenn Sie nur iOS 8 unterstützen müssen, ist nur eine Problemumgehung erforderlich.

0xced
quelle
2
Vielen Dank. Nur Workaround # 2 funktioniert für mich in Xcode 7 und iOS 8.
Surfrider
3
Ich bestätige, dass die Problemumgehung für iOS 8 auch für iOS 9 gültig ist.
Michael Pirotte
1
Ich sehe definitiv dasselbe auf Xcode 7 - die Problemumgehung für Benutzerattribute war in Ordnung. Vielen Dank!
Geoffrey Wiseman
manuelles Zurücksetzen der tintColor in awakeFromNib hat es geschafft! (Das Bild wurde auch im .xcassets-Katalog auf Vorlage gesetzt, andernfalls müssten Sie aus dem Original ein Vorlagenbild erstellen.) Vielen Dank!!
Hufeisen7
15

Wenn Sie imageView RenderingMode so einstellen, dass die Farbtonfarbe im Storyboard verwendet wird, kann dies auf einen Einzeiler reduziert werden:

[self.imageView setImage:[self.imageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]];

Dann können das Bild und die Farbtonfarbe im Storyboard festgelegt werden.

Mittelsitzmann
quelle
13

Sie können .xib-Probleme mit einer Erweiterung beheben:

import UIKit

// fixing Bug in XCode
// http://openradar.appspot.com/18448072
extension UIImageView {
    override open func awakeFromNib() {
        super.awakeFromNib()
        self.tintColorDidChange()
    }
}

Quelle: https://gist.github.com/buechner/3b97000a6570a2bfbc99c005cb010bac

Erstaunlich, dieser Fehler gibt es schon seit 4-5 Jahren.

Nikans
quelle
3
Dies sollte als Antwort ausgewählt werden
farzadshbfn
Immer noch ein Fehler und dies behebt ihn immer noch ab iOS 12.0.
Sam Soffes
Immer noch ein Fehler in iOS 12.1
Cesare
Unwirkliche Jungs, unwirklich.
Mat
8

Sie können renderingModeweder von storyboardnoch einstellen xib. Es könnte programmgesteuert darauf zugreifen.

Ex:

UIImage *unSeletedImage = [UIImage imageNamed:@"UnSelected.png"];
selectedImage = [selectedImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
Mani
quelle
3
Ich denke, Sie haben kleine Tippfehler in Ihrem Code gemacht. Die zweite Zeile sollte seinUIImage *selectedImage = [unSeletedImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
Artem Stepanenko
8

Stellen Sie tintColor & Class im Storyboard ein.

//
//  TintColoredImageView.swift
//  TintColoredImageView
//
//  Created by Dmitry Utmanov on 14/07/16.
//  Copyright © 2016 Dmitry Utmanov. All rights reserved.
//

import UIKit

@IBDesignable class TintColoredImageView: UIImageView {

    override var image: UIImage? {
        didSet {
            let _tintColor = self.tintColor
            self.tintColor = nil
            self.tintColor = _tintColor
        }
    }


    override init(frame: CGRect) {
        super.init(frame: frame)
        initialize()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        initialize()
    }

    override init(image: UIImage?) {
        super.init(image: image)
        initialize()
    }

    override init(image: UIImage?, highlightedImage: UIImage?) {
        super.init(image: image, highlightedImage: highlightedImage)
        initialize()
    }

    func initialize() {
        let _tintColor = self.tintColor
        self.tintColor = nil
        self.tintColor = _tintColor
    }

}
Dmitry Coolerov
quelle
Dies ist die einzige Antwort, die bei New Swift funktioniert hat. Danke dir.
Simon Moshenko
Funktioniert bei mir aus irgendeinem seltsamen Grund nicht ... Soll die Farbe im Storyboard aktualisiert werden?
Cesare
4

Es ist sehr einfach zu beheben

Erstellen Sie einfach die Klasse UIImageViewPDF und verwenden Sie sie in Ihrem Storyboard

IB_DESIGNABLE
@interface UIImageViewPDF : UIImageView

@end

@implementation UIImageViewPDF

- (void) didMoveToSuperview
{
    [super didMoveToSuperview];
    self.image = [self.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
    id color = self.tintColor;
    self.tintColor = color;
}

@end
Igor Popov
quelle
3

Eine andere Lösung besteht darin, eine UIImageViewUnterklasse zu erstellen :

final class TemplateImageView: UIImageView {
    override func awakeFromNib() {
        super.awakeFromNib()
        guard let oldImage = image else { return }
        image = nil
        image = oldImage.withRenderingMode(.alwaysTemplate)
    }
}

Setzen Sie dann einfach die Klasse im Interface Builder auf TemplateImageView.

Rudolf Adamkovič
quelle
beste Lösung !!
Irshad Mohamed
2

Einfache Einstellung über Storyboard:

@IBDesignable
public class CustomImageView: UIImageView {
    @IBInspectable var alwaysTemplate: Bool = false {
        didSet {
            if alwaysTemplate {
                self.image = self.image?.withRenderingMode(.alwaysTemplate)
            } else {
                self.image = self.image?.withRenderingMode(.alwaysOriginal)
            }

        }
    }
}

Funktioniert gut unter iOS 10 und Swift 3

Rodrigo
quelle
1

In iOS 9 ist das Festlegen der tintColorEigenschaft in Interface Builder immer noch fehlerhaft.

Beachten Sie, dass eine funktionierende Lösung neben dem Schreiben von Zeilen, die ImageViewEigenschaften direkt ändern, darin besteht, Render As: Template Image im Asset-Katalog festzulegen und z.

[[UIImageView appearanceWhenContainedInInstancesOfClasses:@[[MyView class]]] setTintColor:[UIColor whiteColor]];
Yarp
quelle
1

Ich habe dieses Problem durch Hinzufügen eines Laufzeitattributs tintColorim Interface Builder behoben .

HINWEIS: Sie müssen Ihr Bild weiterhin so einstellen, dass es als Vorlagenbild in Ihrer Datei Images.xcassets gerendert wird.

Geben Sie hier die Bildbeschreibung ein

Sunil Targe
quelle
0

Wenn Sie ein IBOutlet erstellen, können Sie es in Ihrer awakeFromNib-Methode wie folgt ändern ...

self.myImageView.image = [self.myImageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];

Während @ Mobys Antwort korrekter ist, könnte dies prägnanter sein.

amergin
quelle
1
Die Frage war, wie dies im Storyboard (oder xib) und nicht im Code gemacht werden kann.
Artem Stepanenko
@artem - ja, sorry, ich wollte nicht schließen, dass ich eine Antwort auf deine Frage hatte. Nur einen einfachen Weg aufzuzeigen, wie man damit durch ein IBOutlet umgehen kann
Amergin
0

Verrückt, dieser Fehler ist immer noch in iOS 12.1! Für Storyboards / Xibs: Das Hinzufügen eines Tags zur UIImageView kann eine schnelle Lösung sein.

Swift 4.2

view.viewWithTag(1)?.tintColorDidChange()
Jayden Irwin
quelle
0
extension UIImageView {

   @IBInspectable var renderModeTemplate : Bool {
       get{
           return image?.renderingMode == .alwaysTemplate
       }

       set{
          image = image?.withRenderingMode(newValue ? .alwaysTemplate:.alwaysOriginal)
       }
   }
}

Wählen Sie im Storyboard UIImageView und dann Inspector aus und setzen Sie property renderModeTemplate= On In Storyboard

Ks 2000
quelle