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


Ответы:


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, необходимо только одно временное решение.


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


0

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

import UIKit

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.