Est-il possible de modifier un UIImage
d'un renderingMode
à partir d'un éditeur de storyboard ou xib?
L'objectif est d'appliquer tintColor
à l'objet UIImageView
particulier.
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:
Vous pouvez définir le mode de rendu des images non pas dans le fichier .xib
, mais dans une bibliothèque .xcassets
.
Après avoir ajouté une image à une bibliothèque d'actifs, sélectionnez-la et ouvrez l'inspecteur d'attributs situé à droite de Xcode. Recherchez l'attribut "Render As" et définissez-le sur "template".
Après avoir défini le mode de rendu d'une image, vous pouvez ajouter une couleur de nuance à la variable UIImageView
dans un fichier .xib
ou .storyboard
pour 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 constructeur d'interface, mais dans presque tous les cas (que j'ai rencontrés), il s'agit du comportement souhaité.
Quelques points à noter:
UIImageView
. Je n'ai pas approfondi cette question.UIKitComponents
, telles que les images de UIButton
's et UIBarButtonItem
' s.L'utilisation du mode de rendu des modèles avec UIImageView dans un storyboard ou xib est très problématique, à la fois sous iOS 7 et iOS 8.
UIImage n'est pas correctement décodé à partir du storyboard/xib. Si vous inspectez la propriété imageView.image.renderingMode
dans la méthode viewDidLoad
, vous remarquerez qu'elle est toujours UIImageRenderingModeAutomatic
, même si vous la définissez sur Render As Template Image dans votre fichier xcassets.
Pour contourner ce problème, vous devez définir manuellement le mode de rendu:
self.imageView.image = [self.imageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UIImage est correctement décodé et sa propriété renderingMode
reflète ce qui a été choisi dans le fichier xcassets mais l'image n'est pas colorée.
Pour contourner le problème, vous avez deux options:
tintColor
dans le volet Attributs d'exécution définis par l'utilisateur au lieu du volet Inspecteur Attributs.ou
UIColor *tintColor = self.imageView.tintColor;
self.imageView.tintColor = nil;
self.imageView.tintColor = tintColor;
Vous pouvez choisir votre option préférée, les deux teinter correctement l'image.
(Si vous compilez avec Xcode 6.2, il suffit de faire self.imageView.tintColor = self.imageView.tintColor;
mais cela ne fonctionne plus si vous compilez avec Xcode 6.3)
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.
Définir imageView RenderingMode pour utiliser la couleur de teinte dans le scénarimage peut être réduit à une ligne:
[self.imageView setImage:[self.imageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]];
Ensuite, l’image et la couleur de la teinte peuvent être définies dans le Storyboard.
Vous pouvez corriger les problèmes de .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 bogue existe depuis environ 4-5 ans maintenant.
Vous ne pouvez pas définir renderingMode
à partir de storyboard
ou xib
. Il pourrait accéder par programme.
ex:
UIImage *unSeletedImage = [UIImage imageNamed:@"UnSelected.png"];
selectedImage = [selectedImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
Définissez teinteCouleur & Classe 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
}
}
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
Une autre solution consiste à créer une sous-classe UIImageView
:
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
.
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
Dans iOS 9, la définition de la propriété tintColor
dans Interface Builder est toujours problématique.
Notez qu'une solution de travail en plus d'écrire des lignes modifiant directement les propriétés ImageView
consiste à définir Render As: Template Image dans le catalogue d'actifs et à appeler, par exemple:
[[UIImageView appearanceWhenContainedInInstancesOfClasses:@[[MyView class]]] setTintColor:[UIColor whiteColor]];
Fou ce bug est toujours dans iOS 12.1! Pour les storyboards/xibs: Ajouter une balise à UIImageView peut être une solution rapide.
Swift 4.2
view.viewWithTag(1)?.tintColorDidChange()
Si vous créez un IBOutlet, vous pouvez le changer dans votre méthode awakeFromNib comme suit ...
self.myImageView.image = [self.myImageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
Alors que la réponse de @ Moby est plus correcte, cela pourrait être plus succinct.