Modifier le mode de rendu UIImage à partir d'un fichier storyboard / xib

93

Est-il possible de modifier UIImageles a renderingModedepuis un storyboard ou un éditeur xib?

Le but est de s'appliquer tintColorà l' UIImageViewobjet particulier .

Artem Stepanenko
la source

Réponses:

101

Voici comment vous pouvez le faire dans des fichiers .xib ou storyboard:

(Obj-C) Créez une catégorie sur 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) Créez une extension pour 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)
    }
}

Ensuite, dans l'inspecteur d'identité du fichier xib, ajoutez un attribut d'exécution:

entrez la description de l'image ici

Bonhomme de neige
la source
44
Ce que j'aime dans cette réponse, c'est que c'est une réponse à la question.
algal
1
Je préférerais créer une sous-classe UIImageView plutôt que de définir la valeur de clé. Parce que c'est plus facile à configurer et que nous pourrions éviter le paramètre de nombre à la valeur d'énumération. Par exemple: `@implementation TemplateRenderingImageView - (id) initWithCoder: (NSCoder *) aDecoder {self = [super initWithCoder: aDecoder]; if (self) {self.image = [self.image imageWithRenderingMode: UIImageRenderingModeAlwaysTemplate]; } retourne soi; } @ end`
john fantasy
1
Très bonne réponse! Les captures d'écran ont été utiles.
BigSauce
1
Ne fonctionne pas avec Launch Screen.xib bien sûr car vous ne pouvez pas utiliser les attributs d'exécution définis par l'utilisateur avec lui.
Steve Moser
3
hardcoding 2 en tant que valeur est mauvais mauvais mauvais .. L'utilisation du catalogue xcassets est la bonne réponse.
tGilani du
198

Vous pouvez définir le mode de rendu de l'image non pas dans le .xibfichier, mais dans une .xcassetsbibliothèque.

Après avoir ajouté une image à une bibliothèque de ressources, sélectionnez l'image et ouvrez l'inspecteur d'attributs sur le côté droit de Xcode. Recherchez l'attribut «Rendu en tant que» et définissez-le sur «modèle».

Après avoir défini le mode de rendu d'une image, vous pouvez ajouter une couleur de teinte UIImageViewdans un fichier .xibou .storyboardpour ajuster la couleur de l'image.

Cela définit la propriété sur l'image partout où elle est utilisée plutôt que dans un seul fichier de générateur d'interface, mais dans presque tous les cas (que j'ai rencontrés), c'est le comportement que vous souhaitez.

Capture d'écran de Xcode montrant l'inspecteur d'attributs pour une image

Quelques points à noter:

  • La couleur de l'image ne semble pas avoir changé dans le générateur d'interface (à partir de Xcode 6.1.1) mais fonctionnera lorsque l'application est exécutée.
  • J'ai rencontré une certaine bugginess avec cette fonctionnalité et dans certaines situations, j'ai dû supprimer et rajouter le fichier UIImageView. Je n'ai pas examiné cela en profondeur.
  • Cela fonctionne également très bien sur d'autres UIKitComponentsimages telles que les images dans UIButton's et UIBarButtonItem' s.
  • Si vous avez un tas d'images blanches qui sont invisibles dans votre bibliothèque de ressources, les transformer en images noires / transparentes et changer le mode de rendu vous rendra la vie jusqu'à 10 fois meilleure.
Anthony Mattox
la source
15
Il semble y avoir un bug avec la couleur de la teinte UIImageView , donc la couleur de teinte n'est pas toujours affichée lors de l'exécution de l'application.
Fogh
@Fogh J'ai aussi eu des bugs incohérents comme ça. Le réglage de la couleur de teinte résout-il ce problème par programme?
Anthony Mattox
2
Je peux confirmer qu'il y a un problème lors du réglage de la couleur de teinte dans IB. Le paramétrer fonctionne par programme. J'ai déposé un bogue # 20305518 pour cela.
Nikolay Derkach
1
@AxelGuilmin Yup. En fait, seul le canal alpha est utilisé, il peut donc s'agir de n'importe quelle couleur tant que la transparence est ce que vous voulez.
Anthony Mattox
1
Cela fonctionne maintenant avec Xcode 7.3 (7D175)! Bien que la réponse acceptée soit une solution de contournement très intuitive, je préfère cette réponse à la place.
nstein
43

L'utilisation du mode de rendu de modèle avec une UIImageView dans un storyboard ou xib est très boguée, à la fois sur iOS 7 et iOS 8.

Sur iOS 7

UIImage n'est pas correctement décodée à partir du storyboard / xib. Si vous inspectez la imageView.image.renderingModepropriété dans la viewDidLoadméthode, vous remarquerez qu'elle l'est toujours UIImageRenderingModeAutomatic, même si vous la définissez sur Render As Template Image dans votre fichier xcassets.

Pour contourner le problème, vous devez définir manuellement le mode de rendu:

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

Sur iOS 8

L'interface utilisateur est correctement décodée et sa renderingModepropriété reflète ce qui a été choisi dans le fichier xcassets mais l'image n'est pas teintée.

Pour contourner le problème, vous avez deux options:

  1. Définissez la tintColorpropriété dans le attributs d'exécution définis utilisateur au lieu du volet de l'inspecteur d'attributs.

ou

  1. Réinitialisez manuellement la teinte Couleur:
UIColor *tintColor = self.imageView.tintColor;
self.imageView.tintColor = nil;
self.imageView.tintColor = tintColor;

Vous pouvez choisir votre option préférée, les deux teignant correctement l'image.

(Si vous compilez avec Xcode 6.2, faites simplement self.imageView.tintColor = self.imageView.tintColor; mais cela ne fonctionne plus si vous compilez avec Xcode 6.3)

Conclusion

Si vous devez prendre en charge à la fois iOS 7 et iOS 8, vous aurez besoin des deux solutions de contournement. Si vous devez uniquement prendre en charge iOS 8, une seule solution de contournement est nécessaire.

0xced
la source
2
Merci. Seule la solution de contournement n ° 2 fonctionne pour moi dans Xcode 7 et iOS 8.
surfrider
3
Je confirme que la solution de contournement pour iOS 8 est également valable pour iOS 9.
Michael Pirotte
1
Je vois certainement la même chose sur Xcode 7 - la solution de contournement des attributs utilisateur était bien. Merci!
Geoffrey Wiseman
la réinitialisation manuelle du tintColor dans awakeFromNib l'a fait! (l'image a également été définie comme modèle dans le catalogue .xcassets, sinon vous devrez créer une image modèle à partir de l'original). Merci!!
horseshoe7
15

La définition de imageView RenderingMode pour utiliser la couleur de teinte dans le storyboard peut être réduite à une seule ligne:

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

Ensuite, l'image et la couleur de teinte peuvent toutes être définies dans le Storyboard.

intermédiaire
la source
13

Vous pouvez résoudre les problèmes .xib avec une extension:

import UIKit

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

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

Incroyable, ce bug existe depuis 4 à 5 ans maintenant.

Nikans
la source
3
Cela devrait être sélectionné comme réponse
farzadshbfn
Encore un bogue et cela le corrige toujours à partir d'iOS 12.0.
Sam Soffes
Encore un bug dans iOS 12.1
Cesare
Des gars irréels, irréels.
Mat
8

Vous ne pouvez pas définir renderingModeà partir de storyboardou xib. Il pourrait accéder par programme.

ex:

UIImage *unSeletedImage = [UIImage imageNamed:@"UnSelected.png"];
selectedImage = [selectedImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
Mani
la source
3
Je pense que vous avez fait de petites fautes de frappe dans votre code. La deuxième ligne devrait êtreUIImage *selectedImage = [unSeletedImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
Artem Stepanenko
8

Définissez tintColor & Class dans Storyboard.

//
//  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
la source
C'est la seule réponse qui a fonctionné sur le nouveau swift. Je vous remercie.
Simon Moshenko
Cela ne fonctionne pas pour moi pour une raison étrange ... Est-ce censé mettre à jour la couleur du storyboard?
Cesare
4

C'est très facile à réparer

Créez simplement la classe UIImageViewPDF et utilisez-la dans votre 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
la source
3

Une autre solution consiste à créer une UIImageViewsous - classe:

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

Ensuite, définissez simplement la classe dans Interface Builder sur TemplateImageView.

Rudolf Adamkovič
la source
meilleure solution !!
Irshad Mohamed
2

Un moyen simple d'être défini à partir de 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)
            }

        }
    }
}

Fonctionne bien sur iOS 10 et Swift 3

Rodrigo
la source
1

Dans iOS 9, le paramètre tintColor propriété dans Interface Builder est toujours boguée.

Notez qu'une solution de travail en plus d'écrire des lignes modifiant directement les ImageViewpropriétés est de définir Render As: Template Image dans le catalogue d'actifs, et d'appeler par exemple:

[[UIImageView appearanceWhenContainedInInstancesOfClasses:@[[MyView class]]] setTintColor:[UIColor whiteColor]];
yarp
la source
1

J'ai résolu ce problème en ajoutant un attribut d'exécution tintColor dans le générateur d'interface.

REMARQUE: vous devrez toujours définir votre image pour qu'elle soit rendue en tant qu'image modèle dans votre fichier Images.xcassets.

entrez la description de l'image ici

Sunil Targe
la source
0

Si vous créez un IBOutlet, vous pouvez le modifier dans votre méthode awakeFromNib comme ceci ...

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

Bien que la réponse de @ Moby soit plus correcte, cela pourrait être plus succinct.

amergine
la source
1
La question était de savoir comment faire cela dans le storyboard (ou xib), pas dans le code.
Artem Stepanenko
@artem - ouais, désolé, je ne voulais pas en déduire que j'avais une réponse à votre question. Soulignant simplement un moyen simple de gérer cela via un IBOutlet
amergin
0

Fou ce bug est toujours dans iOS 12.1! Pour les storyboards / xibs: l'ajout d'une balise à UIImageView peut être une solution rapide.

Swift 4.2

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

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

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

Dans le storyboard, sélectionnez UIImageView et sélectionnez l'inspecteur, définissez property renderModeTemplate= On In Storyboard

Ks 2000
la source
0

Comme Rudolf l'a également mentionné ci - dessus , je définirais une classe simple, comme ceci:

import UIKit

@IBDesignable class TintImage: UIImageView{
    override func layoutSubviews() {
        super.layoutSubviews()
 
        image = image?.withRenderingMode(.alwaysTemplate)
    }
}

Après cette définition, ajoutez simplement une vue d'image au storyboard et sélectionnez sa classe personnalisée en tant que TintImage. Cela activera la sélection "Teinte" dans le storyboard.

JustADeveloper
la source