Modificar el modo de representación de UIImage desde un archivo storyboard / xib

93

¿Es posible modificar un UIImage's renderingModede un editor de guión gráfico o xib?

El objetivo es aplicar tintColoral UIImageViewobjeto en particular .

Artem Stepanenko
fuente

Respuestas:

101

Así es como puede hacerlo en archivos .xib o storyboard:

(Obj-C) Cree una categoría en 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) Cree una extensión para 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)
    }
}

Luego, en el Inspector de identidad en el archivo xib, agregue un atributo de tiempo de ejecución:

ingrese la descripción de la imagen aquí

Monigote de nieve
fuente
44
Lo que me encanta de esta respuesta es que es una respuesta a la pregunta.
alga
1
Preferiría crear una subclase UIImageView en lugar de realizar la configuración del valor clave. Porque es más fácil de configurar y podríamos evitar la configuración del número en el valor de enumeración. Por ejemplo: `@implementation TemplateRenderingImageView - (id) initWithCoder: (NSCoder *) aDecoder {self = [super initWithCoder: aDecoder]; if (self) {self.image = [self.image imageWithRenderingMode: UIImageRenderingModeAlwaysTemplate]; } return self; } @ end`
john fantasy
1
¡Gran respuesta! Las capturas de pantalla fueron útiles.
BigSauce
1
No funciona con Launch Screen.xib, por supuesto, porque no puede usar atributos de tiempo de ejecución definidos por el usuario con él.
Steve Moser
3
codificar 2 como valor es malo, malo, malo. El uso del catálogo de xcassets es la respuesta correcta.
tGilani
198

Puede establecer el modo de representación de imágenes no en el .xibarchivo, sino en una .xcassetsbiblioteca.

Después de agregar una imagen a una biblioteca de activos, seleccione la imagen y abra el inspector de atributos en el lado derecho de Xcode. Busque el atributo 'Renderizar como' y establézcalo en 'plantilla'.

Después de configurar el modo de representación de una imagen, se puede añadir un color de tinte a la UIImageViewde una .xibo.storyboard archivo para ajustar el color de la imagen.

Esto establece la propiedad en la imagen donde sea que se use en lugar de solo en un archivo de generador de interfaz, pero en casi todos los casos (que he encontrado) este es el comportamiento que desea.

Captura de pantalla de Xcode que muestra el inspector de atributos de una imagen

Algunas cosas a tener en cuenta:

  • El color de la imagen no parecerá haber cambiado en el generador de interfaces (a partir de Xcode 6.1.1) pero funcionará cuando se ejecute la aplicación.
  • He experimentado algunos errores con esta función y, en algunas situaciones, he tenido que eliminar y volver a agregar el UIImageView. No he mirado tan profundamente.
  • Esto también funciona muy bien en otras UIKitComponentsimágenes como UIButtonlas de y UIBarButtonItem.
  • Si tiene un montón de imágenes en blanco que son invisibles en su biblioteca de activos, convertirlas en imágenes negras / transparentes y cambiar el modo de renderizado hará que su vida sea hasta 10 veces mejor.
Anthony Mattox
fuente
15
Parece que hay un error con el color de tinte activado UIImageView, por lo que el color de tinte no siempre se muestra al ejecutar la aplicación.
Fogh
@Fogh También he tenido algunos errores inconsistentes como ese. ¿La configuración del color del tinte soluciona esto mediante programación?
Anthony Mattox
2
Puedo confirmar que hay un problema al configurar el color del tinte en IB. Configurarlo mediante programación funciona. Presenté un error # 20305518 para él.
Nikolay Derkach
1
@AxelGuilmin Sí. En realidad, solo se usa el canal alfa, por lo que podría ser de cualquier color siempre que la transparencia sea la que desee.
Anthony Mattox
1
¡Funciona ahora con Xcode 7.3 (7D175)! Aunque la respuesta aceptada es una solución muy intuitiva, prefiero esta respuesta.
nstein
43

Usar el modo de renderizado de plantillas con UIImageView en un guión gráfico o xib tiene muchos errores, tanto en iOS 7 como en iOS 8.

En iOS 7

El UIImage no se decodifica correctamente desde el guión gráfico / xib. Si inspecciona la imageView.image.renderingModepropiedad en el viewDidLoadmétodo, notará que siempre lo es UIImageRenderingModeAutomatic, incluso si lo establece en Renderizar como imagen de plantilla en su archivo xcassets.

Para solucionarlo, debe configurar manualmente el modo de renderizado:

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

En iOS 8

El UIImage está correctamente decodificado y su renderingModepropiedad refleja lo que se eligió en el archivo xcassets, pero la imagen no está teñida.

Para solucionarlo, tiene dos opciones:

  1. Establezca la tintColorpropiedad en Atributos de tiempo de ejecución definidos por el usuario en lugar del panel del inspector de atributos.

o

  1. Restablezca manualmente el tintColor:
UIColor *tintColor = self.imageView.tintColor;
self.imageView.tintColor = nil;
self.imageView.tintColor = tintColor;

Puede elegir su opción preferida, ambos matizan correctamente la imagen.

(Si está compilando con Xcode 6.2, solo hacerlo self.imageView.tintColor = self.imageView.tintColor;es suficiente, pero esto ya no funciona si está compilando con Xcode 6.3)

Conclusión

Si necesita admitir tanto iOS 7 como iOS 8, necesitará ambas soluciones. Si solo tiene que admitir iOS 8, solo se necesita una solución alternativa.

0xced
fuente
2
Gracias. La única solución alternativa n. ° 2 me funciona en Xcode 7 e iOS 8.
surfrider
3
Confirmo que la solución para iOS 8 también es válida para iOS 9.
Michael Pirotte
1
Definitivamente estoy viendo lo mismo en Xcode 7: la solución alternativa de atributos de usuario estaba bien. ¡Gracias!
Geoffrey Wiseman
restableciendo manualmente el tintColor en awakeFromNib lo hizo! (la imagen también se configuró como plantilla en el catálogo .xcassets, de lo contrario, tendría que hacer una imagen de plantilla a partir del original). ¡¡Gracias!!
herradura 7
15

La configuración de imageView RenderingMode para usar el color de tinte en el guión gráfico se puede reducir a una sola línea:

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

Luego, la imagen y el color del tinte se pueden configurar en el Storyboard.

Middleseatman
fuente
13

Puede solucionar problemas de .xib con una extensión:

import UIKit

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

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

Increíble, este error ha existido durante unos 4-5 años.

nikans
fuente
3
Esto debe seleccionarse como la respuesta
farzadshbfn
Sigue siendo un error y todavía lo soluciona a partir de iOS 12.0.
Sam Soffes
Sigue siendo un error en iOS 12.1
Cesare
Chicos irreales, irreales.
Mat
8

No puede establecer renderingModeni desde storyboardni xib. Podría acceder mediante programación.

ex:

UIImage *unSeletedImage = [UIImage imageNamed:@"UnSelected.png"];
selectedImage = [selectedImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
Mani
fuente
3
Creo que ha cometido pequeños errores tipográficos en su código. La segunda línea debería serUIImage *selectedImage = [unSeletedImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
Artem Stepanenko
8

Establezca tintColor & Class en 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
fuente
Esta es la única respuesta que funcionó en new swift. Gracias.
Simon Moshenko
No me funciona por alguna extraña razón ... ¿Se supone que debe actualizar el color en el guión gráfico?
Cesare
4

Es muy facil de arreglar

Simplemente cree la clase UIImageViewPDF y úsela en su guión gráfico

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
fuente
3

Otra solución es crear una UIImageViewsubclase:

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

Luego, configure la clase en Interface Builder en TemplateImageView.

Rudolf Adamkovič
fuente
mejor solución !!
Irshad Mohamed
2

Forma sencilla de configurar desde 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)
            }

        }
    }
}

Funciona bien en iOS 10 y Swift 3

Rodrigo
fuente
1

En iOS 9, la configuración de la tintColorpropiedad en Interface Builder todavía tiene errores.

Tenga en cuenta que una solución de trabajo además de escribir líneas que modifican directamente las ImageViewpropiedades es establecer Renderizar como: Imagen de plantilla en el catálogo de activos y llamar, por ejemplo:

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

Solucioné este problema agregando un atributo de tiempo de ejecución tintColoren el generador de interfaces.

NOTA: Aún necesitará configurar su imagen para que se renderice como una imagen de plantilla en su archivo Images.xcassets.

ingrese la descripción de la imagen aquí

Sunil Targe
fuente
0

Si crea un IBOutlet, puede cambiarlo en su método awakeFromNib así ...

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

Si bien la respuesta de @ Moby es más correcta, esto podría ser más conciso.

amergin
fuente
1
La pregunta era cómo hacer esto en storyboard (o xib), no en código.
Artem Stepanenko
@artem: sí, lo siento, no quería inferir que tenía una respuesta a tu pregunta. Simplemente señalando una forma sencilla de lidiar con esto a través de un IBOutlet
partir del
0

¡Loco, este error todavía está en iOS 12.1! Para guiones gráficos / xibs: agregar una etiqueta a UIImageView puede ser una solución rápida.

Rápido 4.2

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

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

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

En el guión gráfico, seleccione UIImageView y seleccione el inspector, establezca la propiedad renderModeTemplate= On En el guión gráfico

Ks 2000
fuente
0

Como Rudolf también mencionó anteriormente , definiría una clase simple, como esta:

import UIKit

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

Después de esta definición, simplemente agregue una Vista de imagen al guión gráfico y seleccione su clase personalizada como TintImage. Esto activará la selección "Tinte" en el guión gráfico.

JustADeveloper
fuente