Измените режим рендеринга UIImage из файла раскадровки / xib

95

Можно ли изменить UIImage«S renderingModeиз раскадровки или XIb редактор?

Цель - применить tintColorк конкретному UIImageViewобъекту.

Артем Степаненко
источник

Ответы:

101

Вот как это можно сделать в файлах .xib или раскадровке:

(Obj-C) Создайте категорию на 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) Создайте расширение для 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)
    }
}

Затем в Identity Inspector в файле xib добавьте атрибут времени выполнения:

введите описание изображения здесь

Снеговик
источник
44
Что мне нравится в этом ответе, так это то, что это ответ на вопрос.
algal
1
Я бы предпочел создать подкласс UIImageView, а не устанавливать значение ключа. Потому что это проще настроить, и мы могли бы избежать установки числа в значение перечисления. Например: `@implementation TemplateRenderingImageView - (id) initWithCoder: (NSCoder *) aDecoder {self = [super initWithCoder: aDecoder]; if (self) {self.image = [self.image imageWithRenderingMode: UIImageRenderingModeAlwaysTemplate]; } return self; } @ end`
john fantasy
1
Отличный ответ! Скриншоты были полезны.
BigSauce
1
Конечно, не работает с Launch Screen.xib, потому что вы не можете использовать с ним определенные пользователем атрибуты времени выполнения.
Стив Мозер
3
hardcoding 2 как значение плохо плохо плохо .. Использование каталога xcasset - правильный ответ.
tGilani
199

Вы можете установить режим рендеринга изображения не в .xibфайле, а в .xcassetsбиблиотеке.

После добавления изображения в библиотеку ресурсов выберите изображение и откройте инспектор атрибутов в правой части Xcode. Найдите атрибут «Визуализировать как» и установите для него «шаблон».

После установки режима рендеринга изображения вы можете добавить цвет оттенка UIImageViewв файл .xibили, .storyboardчтобы настроить цвет изображения.

Это устанавливает свойство на изображении, где бы оно ни использовалось, а не только в одном файле построителя интерфейса, но почти во всех случаях (с которыми я сталкивался) это именно то поведение, которое вам нужно.

Снимок экрана Xcode, показывающий инспектор атрибутов для изображения

Несколько замечаний:

  • Цвет изображения не изменится в построителе интерфейса (начиная с Xcode 6.1.1), но будет работать при запуске приложения.
  • У меня возникли некоторые проблемы с этой функцией, и в некоторых ситуациях мне приходилось удалять и повторно добавлять файлы UIImageView. Я не вникал в это глубоко.
  • Это также отлично работает с другими, UIKitComponentsнапример изображениями в UIButton's и UIBarButtonItem'.
  • Если у вас есть куча белых изображений, которые невидимы в вашей библиотеке ресурсов, сделав их черными / прозрачными изображениями и изменив режим рендеринга, вы сделаете вашу жизнь в 10 раз лучше.
Энтони Маттокс
источник
15
Кажется, есть ошибка с включенным цветом оттенка UIImageView, поэтому цвет оттенка не всегда отображается при запуске приложения.
Fogh
@Fogh У меня тоже были такие непоследовательные ошибки. Исправляет ли это программная установка цвета оттенка?
Энтони Маттокс,
2
Я могу подтвердить, что есть проблема при установке цвета оттенка в IB. Установка его программно работает. Я зарегистрировал для него ошибку # 20305518.
Николай Деркач
1
@AxelGuilmin Ага. На самом деле используется только альфа-канал, поэтому он может быть любого цвета, если вам нужна прозрачность.
Энтони Маттокс,
1
Теперь он работает с Xcode 7.3 (7D175)! Хотя принятый ответ представляет собой очень интуитивно понятный обходной путь, я предпочитаю этот ответ.
nstein
43

Использование режима рендеринга шаблона с UIImageView в раскадровке или xib очень ошибочно, как на iOS 7, так и на iOS 8.

На iOS 7

UIImage неправильно декодируется из раскадровки / xib. Если вы проверите imageView.image.renderingModeсвойство в viewDidLoadметоде, вы заметите, что оно всегда UIImageRenderingModeAutomatic, даже если вы установите для него значение « Визуализировать как изображение шаблона» в файле xcassets.

Чтобы обойти эту проблему, вам необходимо вручную установить режим рендеринга:

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

На iOS 8

UIImage правильно декодирован, и его renderingModeсвойство отражает то, что было выбрано в файле xcassets, но изображение не окрашено.

Для обходного пути у вас есть два варианта:

  1. Установите tintColorсвойство в определяемых пользователем атрибутах времени выполнения, а не на панели инспектора атрибутов.

или

  1. Вручную сбросьте tintColor:
UIColor *tintColor = self.imageView.tintColor;
self.imageView.tintColor = nil;
self.imageView.tintColor = tintColor;

Вы можете выбрать понравившийся вариант, как правильно подкрасить изображение.

(Если вы компилируете с Xcode 6.2, достаточно просто сделать self.imageView.tintColor = self.imageView.tintColor;, но это больше не работает, если вы компилируете с Xcode 6.3)

Вывод

Если вам нужно поддерживать как iOS 7, так и iOS 8, вам понадобятся оба обходных пути. Если вам нужно поддерживать только iOS 8, необходимо только одно временное решение.

0xced
источник
2
Спасибо. В Xcode 7 и iOS 8 у меня работает только обходной путь №2.
surfrider
3
Я подтверждаю, что обходной путь для iOS 8 также применим и для iOS 9.
Майкл Пиротт,
1
Я определенно вижу то же самое в Xcode 7 - обходной путь атрибута пользователя был в порядке. Благодарность!
Джеффри Уайзман,
ручной сброс tintColor в awakeFromNib сделал это! (изображение было установлено как шаблон в каталоге .xcassets, иначе вам пришлось бы создавать изображение шаблона из оригинала). Благодарность!!
horseshoe7
15

Настройка imageView RenderingMode для использования цвета оттенка в раскадровке может быть уменьшена до однострочного:

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

Затем изображение и цвет оттенка можно установить в раскадровке.

средний сидящий
источник
13

Вы можете исправить проблемы .xib с помощью расширения:

import UIKit

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

Источник: https://gist.github.com/buechner/3b97000a6570a2bfbc99c005cb010bac

Удивительно, но эта ошибка существует уже 4-5 лет.

никанс
источник
3
Это должно быть выбрано в качестве ответа
farzadshbfn
По-прежнему является ошибкой, и это все еще исправляет ее в iOS 12.0.
Sam Soffes
По-прежнему ошибка в iOS 12.1
Cesare
Нереальные ребята, нереальные.
Mat
8

Вы не можете установить renderingModeни из, storyboardни xib. Он мог получить доступ программно.

пример:

UIImage *unSeletedImage = [UIImage imageNamed:@"UnSelected.png"];
selectedImage = [selectedImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
Мани
источник
3
Я думаю, вы допустили небольшие опечатки в своем коде. Вторая строчка должна бытьUIImage *selectedImage = [unSeletedImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
Артем Степаненко
8

Установите tintColor и класс в раскадровке.

//
//  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
    }

}
Дмитрий Колеров
источник
Это единственный ответ, который сработал на новом свифте. Спасибо.
Simon
У меня не работает по какой-то непонятной причине ... А в раскадровке должен обновлять цвет?
Cesare
4

Это очень легко исправить

Просто создайте класс UIImageViewPDF и используйте его в своей раскадровке.

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
Игорь Попов
источник
3

Другое решение - создать UIImageViewподкласс:

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

Затем просто установите класс в Интерфейсном Разработчике на TemplateImageView.

Рудольф Адамкович
источник
лучшее решение !!
Иршад Мохамед
2

Простой способ установки из раскадровки:

@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)
            }

        }
    }
}

Прекрасно работает на iOS 10 и Swift 3

Родриго
источник
1

В iOS 9 установка tintColor свойства в Интерфейсном Разработчике все еще содержит ошибки.

Обратите внимание, что рабочим решением помимо написания строк, непосредственно изменяющих ImageViewсвойства, является установка Render As: Template Image в каталоге ресурсов и вызов, например:

[[UIImageView appearanceWhenContainedInInstancesOfClasses:@[[MyView class]]] setTintColor:[UIColor whiteColor]];
ворчание
источник
1

Я решил эту проблему, добавив атрибут времени выполнения tintColor в построитель интерфейса.

ПРИМЕЧАНИЕ. Вам все равно необходимо настроить отображение изображения в качестве шаблона изображения в файле Images.xcassets.

введите описание изображения здесь

Сунил Тарге
источник
0

Если вы создаете IBOutlet, вы можете изменить его в своем методе awakeFromNib следующим образом ...

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

Хотя ответ @Moby более правильный - он может быть более сжатым.

амерджин
источник
1
Вопрос был в том, как это сделать в раскадровке (или xib), а не в коде.
Артем Степаненко
@artem - да, извините, я не имел в виду, что у меня есть ответ на ваш вопрос. Просто укажу на простой способ справиться с этим через IBOutlet
начало
0

Безумно, эта ошибка все еще присутствует в iOS 12.1! Для раскадровок / xibs: добавление тега в UIImageView может быть быстрым решением.

Swift 4.2

view.viewWithTag(1)?.tintColorDidChange()
Джейден Ирвин
источник
0
extension UIImageView {

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

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

В раскадровке выберите UIImageView и выберите инспектор, установите свойство renderModeTemplate= On In Storyboard

Ks 2000
источник
0

Как упоминал выше Рудольф , я бы определил простой класс, например:

import UIKit

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

После этого определения просто добавьте представление изображения в раскадровку и выберите его настраиваемый класс как TintImage. Это активирует выбор «Оттенок» в раскадровке.

JustADeveloper
источник