Modificar UIImage renderingMode de um storyboard / arquivo xib

93

É possível modificar um UIImage's renderingModede um editor de storyboard ou xib?

O objetivo é aplicar tintColorao UIImageViewobjeto específico .

Artem Stepanenko
fonte

Respostas:

101

Veja como você pode fazer isso em arquivos .xib ou storyboard:

(Obj-C) Crie uma categoria em 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) Crie uma extensão 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)
    }
}

Em seguida, no Identity Inspector do arquivo xib, adicione um atributo runtime:

insira a descrição da imagem aqui

Boneco de neve
fonte
44
O que adoro nesta resposta é que é uma resposta à pergunta.
algal
1
Eu preferiria criar uma subclasse UIImageView em vez de fazer a configuração do valor da chave. Porque é mais fácil de configurar e podemos evitar a configuração do número para o valor de enumeração. Por exemplo: `@implementation TemplateRenderingImageView - (id) initWithCoder: (NSCoder *) aDecoder {self = [super initWithCoder: aDecoder]; if (self) {self.image = [self.image imageWithRenderingMode: UIImageRenderingModeAlwaysTemplate]; } retornar a si mesmo; } @ end`
john fantasy
1
Ótima resposta! As imagens foram úteis.
BigSauce
1
Não funciona com Launch Screen.xib, é claro, porque você não pode usar atributos de tempo de execução definidos pelo usuário com ele.
Steve Moser,
3
codificar 2 como um valor é ruim ruim ruim .. O uso do catálogo xcassets é a resposta certa.
tGilani
198

Você pode definir o modo de renderização da imagem não no .xibarquivo, mas em uma .xcassetsbiblioteca.

Depois de adicionar uma imagem a uma biblioteca de ativos, selecione a imagem e abra o inspetor de atributos no lado direito do Xcode. Encontre o atributo 'Renderizar como' e defina-o como 'template'.

Depois de definir o modo de renderização de uma imagem, você pode adicionar uma cor de matiz UIImageViewem um arquivo .xibou .storyboardpara ajustar a cor da imagem.

Isso define a propriedade na imagem onde quer que seja usada, em vez de apenas em um arquivo do construtor de interface, mas em quase todos os casos (que encontrei) este é o comportamento que você deseja.

Captura de tela do Xcode mostrando o inspetor de atributos de uma imagem

Algumas coisas a serem observadas:

  • A cor da imagem não parecerá ter mudado no construtor de interface (a partir do Xcode 6.1.1), mas funcionará quando o aplicativo for executado.
  • Eu percebi alguns erros com esse recurso e, em algumas situações, tive que remover e adicionar novamente o UIImageView. Eu não olhei tão profundamente.
  • Isso também funciona muito bem em outras UIKitComponentsimagens, como em UIButton'se UIBarButtonItem' s.
  • Se você tiver um monte de imagens brancas que são invisíveis em sua biblioteca de ativos, torná-las imagens pretas / transparentes e alterar o modo de renderização tornará sua vida até 10x melhor.
Anthony Mattox
fonte
15
Parece haver um bug com a cor da tonalidade ativada UIImageView, então a cor da tonalidade nem sempre é mostrada ao executar o aplicativo.
Fogh de
@Fogh Também tive alguns bugs inconsistentes como esse. Definir a cor de matiz de maneira programática corrige isso?
Anthony Mattox de
2
Posso confirmar que há um problema ao definir a cor de tonalidade em IB. Configurá-lo programaticamente funciona. Registrei um bug # 20305518 para ele.
Nikolay Derkach
1
@AxelGuilmin Sim. Na verdade, apenas o canal alfa é usado, então pode ser de qualquer cor, desde que a transparência seja o que você deseja.
Anthony Mattox
1
Agora funciona com o Xcode 7.3 (7D175)! Embora a resposta aceita seja uma solução alternativa muito intuitiva, prefiro esta resposta.
nstein
43

Usar o modo de renderização de modelo com um UIImageView em um storyboard ou xib é muito problemático, tanto no iOS 7 quanto no iOS 8.

No iOS 7

O UIImage não foi decodificado corretamente do storyboard / xib. Se você inspecionar a imageView.image.renderingModepropriedade no viewDidLoadmétodo, perceberá que é sempre UIImageRenderingModeAutomatic, mesmo se você configurá-la para Render As Template Image em seu arquivo xcassets.

Para contornar o problema, você deve definir manualmente o modo de renderização:

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

No iOS 8

O UIImage é decodificado corretamente e sua renderingModepropriedade reflete o que foi escolhido no arquivo xcassets, mas a imagem não é colorida.

Para contornar o problema, você tem duas opções:

  1. Defina a tintColorpropriedade nos Atributos de Tempo de Execução Definidos pelo Usuário em vez do painel do inspetor Atributos.

ou

  1. Redefina manualmente o tintColor:
UIColor *tintColor = self.imageView.tintColor;
self.imageView.tintColor = nil;
self.imageView.tintColor = tintColor;

Você pode escolher sua opção preferida, tanto tingir corretamente a imagem.

(Se você estiver compilando com o Xcode 6.2, basta fazer self.imageView.tintColor = self.imageView.tintColor; é suficiente, mas isso não funciona mais se você estiver compilando com o Xcode 6.3)

Conclusão

Se precisar de suporte para iOS 7 e iOS 8, você precisará de ambas as soluções alternativas. Se você só precisa oferecer suporte ao iOS 8, apenas uma solução alternativa é necessária.

0xced
fonte
2
Obrigado. Apenas a solução alternativa # 2 está funcionando para mim no Xcode 7 e iOS 8.
surfrider
3
Confirmo que a solução alternativa para iOS 8 também é válida para iOS 9.
Michael Pirotte
1
Estou definitivamente vendo a mesma coisa no Xcode 7 - a solução alternativa para o atributo do usuário funcionou. Obrigado!
Geoffrey Wiseman
redefinir manualmente o tintColor em awakeFromNib conseguiu! (a imagem foi definida como modelo no catálogo .xcassets também, caso contrário, você teria que fazer uma imagem de modelo do original). Obrigado!!
ferradura 7 de
15

A configuração de imageView RenderingMode para usar a cor de matiz no storyboard pode ser reduzida a uma linha:

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

Então, a imagem e a cor da tonalidade podem ser definidas no Storyboard.

intermediário
fonte
13

Você pode corrigir problemas .xib com uma extensão:

import UIKit

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

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

Incrível, esse bug já existe há 4-5 anos.

nikans
fonte
3
Deve ser selecionado como a resposta
farzadshbfn
Ainda é um bug e isso ainda corrige a partir do iOS 12.0.
Sam Soffes,
Ainda um bug no iOS 12.1
Cesare
Caras irreais, irreais.
Mat
8

Você não pode definir renderingModede storyboardou xib. Ele pode acessar programaticamente.

ex:

UIImage *unSeletedImage = [UIImage imageNamed:@"UnSelected.png"];
selectedImage = [selectedImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
Mani
fonte
3
Acho que você cometeu pequenos erros de digitação em seu código. A segunda linha deve serUIImage *selectedImage = [unSeletedImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
Artem Stepanenko,
8

Defina tintColor e classe no 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
fonte
Esta é a única resposta que funcionou no novo swift. Obrigado.
Simon Moshenko
Não funciona para mim por algum motivo estranho ... É suposto para atualizar a cor no storyboard?
Cesare
4

É muito fácil de consertar

Basta criar a classe UIImageViewPDF e usá-la em seu 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
fonte
3

Outra solução é criar uma UIImageViewsubclasse:

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

Em seguida, defina a classe no Interface Builder como TemplateImageView.

Rudolf Adamkovič
fonte
melhor solução !!
Irshad Mohamed
2

Maneira simples de definir a partir do 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 bem no iOS 10 e Swift 3

Rodrigo
fonte
1

Na configuração do iOS 9, a tintColorpropriedade no Interface Builder ainda apresenta erros.

Observe que uma solução de trabalho além de escrever linhas que modificam diretamente as ImageViewpropriedades é definir Render As: Template Image no catálogo de ativos e chamar, por exemplo:

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

Resolvi esse problema adicionando o atributo runtime tintColorno construtor de interface.

NOTA: Você ainda precisará definir sua imagem para ser renderizada como uma imagem de modelo em seu arquivo Images.xcassets.

insira a descrição da imagem aqui

Sunil Targe
fonte
0

Se você criar um IBOutlet, você pode alterá-lo em seu método awakeFromNib assim ...

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

Embora a resposta de @Moby seja mais correta - pode ser mais sucinta.

Amergin
fonte
1
A questão era como fazer isso no storyboard (ou xib), não no código.
Artem Stepanenko
@artem - sim, desculpe, eu não queria inferir que tinha uma resposta para sua pergunta. Apenas apontando uma maneira simples de lidar com isso por meio de um IBOutlet
amergin
0

Louco esse bug ainda está no iOS 12.1! Para storyboards / xibs: Adicionar uma tag ao UIImageView pode ser uma solução rápida.

Swift 4.2

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

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

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

No storyboard, selecione UIImageView e selecione o inspetor, defina a propriedade renderModeTemplate= On No Storyboard

Ks 2.000
fonte