Изменить цвет png в кнопках - ios

95

У меня есть набор иконок, которые я создал, которые представляют собой прозрачные белые PNG:

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

А мне бы хотелось подкрасить их в другие цвета. Такие как синий, серый и т. Д.

Я заметил, что при нажатии / касании они автоматически становятся серыми. Итак, я предполагаю, что могу изменить этот серый цвет на все, что мне нравится, одним касанием или его нормальным состоянием:

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

Как лучше всего этого добиться?

Галактика
источник

Ответы:

231

Следующий код установит цвет оттенка для нормального состояния кнопки:

Для Swift 4 и новее:

let origImage = UIImage(named: "imageName")
let tintedImage = origImage?.withRenderingMode(.alwaysTemplate)
btn.setImage(tintedImage, for: .normal)
btn.tintColor = .red

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


Старые версии

Для Swift 3:

let origImage = UIImage(named: "imageName")
let tintedImage = origImage?.withRenderingMode(.alwaysTemplate)
btn.setImage(tintedImage, forState: .normal)
btn.tintColor = .redColor

Для Swift 2: см. Историю изменений.

Yuvrajsinh
источник
Замечательно! Но как вернуться к исходному изображению (без оттенков)?
Marsman
@Marsman, если вы посмотрите на мое решение, originaImage представляет исходное изображение, а tintedImage представляет тонированную версию исходного изображения, поэтому вы не заменяете исходное изображение, а создаете его новую версию, и у вас будет две версии одного и того же изображения, которые вы можете использовать как для ваших
нужд
не работает в iOS 11 с xcode 9.1. Когда Добавить цвет оттенка, он полностью меняет цвет imageView.
Vineesh TP
Различные правки внесли неточности в этот ответ.
Эрик Айя
13

iOS 7 представила свойство tintColor для представлений (включая UIImageView). Однако вам также необходимо установить тип рендеринга в UIImage, чтобы это имело какой-либо эффект.

UIImage *originalImage = [UIImage imageNamed:@"image.png"];
UIImage *tintedImage = [originalImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UIImageView *imageView = [[UIImageView alloc] initWithImage:tintedImage];

imageView.tintColor = [UIColor grayColor];
[self.view addSubview:imageView];

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

JoGoFo
источник
10

Вы можете использовать это расширение:

import UIKit

extension CGContext {

    func fill(_ rect: CGRect,
              with mask: CGImage,
              using color: CGColor) {

        saveGState()
        defer { restoreGState() }

        translateBy(x: 0.0, y: rect.size.height)
        scaleBy(x: 1.0, y: -1.0)
        setBlendMode(.normal)

        clip(to: rect, mask: mask)

        setFillColor(color)
        fill(rect)
    }
}

extension UIImage {

    func filled(with color: UIColor) -> UIImage {
        let rect = CGRect(origin: .zero, size: self.size)
        guard let mask = self.cgImage else { return self }

        if #available(iOS 10.0, *) {
            let rendererFormat = UIGraphicsImageRendererFormat()
            rendererFormat.scale = self.scale

            let renderer = UIGraphicsImageRenderer(size: rect.size,
                                                   format: rendererFormat)
            return renderer.image { context in
                context.cgContext.fill(rect,
                                       with: mask,
                                       using: color.cgColor)
            }
        } else {
            UIGraphicsBeginImageContextWithOptions(rect.size,
                                                   false,
                                                   self.scale)
            defer { UIGraphicsEndImageContext() }

            guard let context = UIGraphicsGetCurrentContext() else { return self }

            context.fill(rect,
                         with: mask,
                         using: color.cgColor)
            return UIGraphicsGetImageFromCurrentImageContext() ?? self
        }
    }
}
Илья Халяпин
источник
2
У меня это тоже не работает. Когда я использую этот метод, все, что я вижу, - это цвет, а не изображение, окрашенное в этот цвет.
Moebius
9

Для изменения оттенка изображения ( пика , классическое изображение , фото ) используйте:

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

Swift 2

public extension UIImage {
    /**
     Tint, Colorize image with given tint color<br><br>
     This is similar to Photoshop's "Color" layer blend mode<br><br>
     This is perfect for non-greyscale source images, and images that have both highlights and shadows that should be preserved<br><br>
     white will stay white and black will stay black as the lightness of the image is preserved<br><br>

     <img src="http://yannickstephan.com/easyhelper/tint1.png" height="70" width="120"/>

     **To**

     <img src="http://yannickstephan.com/easyhelper/tint2.png" height="70" width="120"/>

     - parameter tintColor: UIColor

     - returns: UIImage
     */
    public func tintPhoto(tintColor: UIColor) -> UIImage {

        return modifiedImage { context, rect in
            // draw black background - workaround to preserve color of partially transparent pixels
            CGContextSetBlendMode(context, .Normal)
            UIColor.blackColor().setFill()
            CGContextFillRect(context, rect)

            // draw original image
            CGContextSetBlendMode(context, .Normal)
            CGContextDrawImage(context, rect, self.CGImage)

            // tint image (loosing alpha) - the luminosity of the original image is preserved
            CGContextSetBlendMode(context, .Color)
            tintColor.setFill()
            CGContextFillRect(context, rect)

            // mask by alpha values of original image
            CGContextSetBlendMode(context, .DestinationIn)
            CGContextDrawImage(context, rect, self.CGImage)
        }
    }
    /**
     Tint Picto to color

     - parameter fillColor: UIColor

     - returns: UIImage
     */
    public func tintPicto(fillColor: UIColor) -> UIImage {

        return modifiedImage { context, rect in
            // draw tint color
            CGContextSetBlendMode(context, .Normal)
            fillColor.setFill()
            CGContextFillRect(context, rect)

            // mask by alpha values of original image
            CGContextSetBlendMode(context, .DestinationIn)
            CGContextDrawImage(context, rect, self.CGImage)
        }
    }
    /**
     Modified Image Context, apply modification on image

     - parameter draw: (CGContext, CGRect) -> ())

     - returns: UIImage
     */
    private func modifiedImage(@noescape draw: (CGContext, CGRect) -> ()) -> UIImage {

        // using scale correctly preserves retina images
        UIGraphicsBeginImageContextWithOptions(size, false, scale)
        let context: CGContext! = UIGraphicsGetCurrentContext()
        assert(context != nil)

        // correctly rotate image
        CGContextTranslateCTM(context, 0, size.height);
        CGContextScaleCTM(context, 1.0, -1.0);

        let rect = CGRectMake(0.0, 0.0, size.width, size.height)

        draw(context, rect)

        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
}

UPD

Swift 3

extension UIImage {

    /**
     Tint, Colorize image with given tint color<br><br>
     This is similar to Photoshop's "Color" layer blend mode<br><br>
     This is perfect for non-greyscale source images, and images that have both highlights and shadows that should be preserved<br><br>
     white will stay white and black will stay black as the lightness of the image is preserved<br><br>

     <img src="http://yannickstephan.com/easyhelper/tint1.png" height="70" width="120"/>

     **To**

     <img src="http://yannickstephan.com/easyhelper/tint2.png" height="70" width="120"/>

     - parameter tintColor: UIColor

     - returns: UIImage
     */
    func tintPhoto(_ tintColor: UIColor) -> UIImage {

        return modifiedImage { context, rect in
            // draw black background - workaround to preserve color of partially transparent pixels
            context.setBlendMode(.normal)
            UIColor.black.setFill()
            context.fill(rect)

            // draw original image
            context.setBlendMode(.normal)
            context.draw(cgImage!, in: rect)

            // tint image (loosing alpha) - the luminosity of the original image is preserved
            context.setBlendMode(.color)
            tintColor.setFill()
            context.fill(rect)

            // mask by alpha values of original image
            context.setBlendMode(.destinationIn)
            context.draw(context.makeImage()!, in: rect)
        }
    }

    /**
     Tint Picto to color

     - parameter fillColor: UIColor

     - returns: UIImage
     */
    func tintPicto(_ fillColor: UIColor) -> UIImage {

        return modifiedImage { context, rect in
            // draw tint color
            context.setBlendMode(.normal)
            fillColor.setFill()
            context.fill(rect)

            // mask by alpha values of original image
            context.setBlendMode(.destinationIn)
            context.draw(cgImage!, in: rect)
        }
    }

    /**
     Modified Image Context, apply modification on image

     - parameter draw: (CGContext, CGRect) -> ())

     - returns: UIImage
     */
    fileprivate func modifiedImage(_ draw: (CGContext, CGRect) -> ()) -> UIImage {

        // using scale correctly preserves retina images
        UIGraphicsBeginImageContextWithOptions(size, false, scale)
        let context: CGContext! = UIGraphicsGetCurrentContext()
        assert(context != nil)

        // correctly rotate image
        context.translateBy(x: 0, y: size.height)
        context.scaleBy(x: 1.0, y: -1.0)

        let rect = CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height)

        draw(context, rect)

        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image!
    }

}
ЯннСтеф
источник
Вы можете сказать мне, как использовать эти методы, как их вызывать?
ashmi123
У меня это совсем не работает. У меня установлен PNG в качестве изображения кнопки. Когда я использую tintPhoto или tintPicto, они просто не работают.
Moebius
если вы добавляете изображение с помощьюRenderingMode (.alwaysTemplate)? @Moebius
YannSteph
Да, и когда я использую любой из методов оттенка, я вижу только цвет. Я даже установил альфа цвета на 0,5 и все еще вижу только цвет. Swift 4
Moebius
Хорошо, примените альфа-канал после оттенка @Moebius
YannSteph
9

Если вы устанавливаете изображение для кнопки, просто перейдите в инспектор атрибутов и измените тип кнопки на системный. Затем установите изображение и измените цвет оттенка. Цвет изображения изменится. Если этого не произошло, проверьте тип кнопки.

Миллигатор
источник
9

Swift 4 или 5

extension UIButton{

    func setImageTintColor(_ color: UIColor) {
        let tintedImage = self.imageView?.image?.withRenderingMode(.alwaysTemplate)
        self.setImage(tintedImage, for: .normal)
        self.tintColor = color
    }

}

Использование:

button.setImage(UIImage(named: "image_name"), for: .normal) // You can set image direct from Storyboard
button.setImageTintColor(UIColor.white)
Крунал Патель
источник
нет никакого метода setImageTintColor для просмотра UIbutton
Khan
Это расширение UIButton. Я создал выше.
Крунал Патель,
6

Если вы используете каталоги ресурсов, вы можете настроить сам ресурс изображения для рендеринга в режиме шаблона. После этого вы можете установить tintColor кнопки в Интерфейсном Разработчике (или в коде), и это должно занять.

Моливейра
источник
Это лучший подход, если вы используете одно и то же изображение в нескольких местах, поскольку вы только один раз устанавливаете изображение в режим шаблона в каталоге активов.
Джонатан Кабрера
Этот подход у меня не сработал. Когда я устанавливаю PNG в качестве изображения шаблона, а затем устанавливаю цвет оттенка, изображение заменяется цветом оттенка.
Moebius
Для меня это тоже лучший подход. Большое спасибо. Простой легкий многоразовый ...
Альпарслан Сельчук Девелиоглу
4

Swift 4

    let origImage = UIImage(named: "check")
    let tintedImage = origImage?.withRenderingMode(.alwaysTemplate)
    buttons[0].setImage(tintedImage, for: .normal)
    buttons[0].tintColor = .red
Ахмед Сафади
источник
3

Если вы используете каталоги ресурсов, вы можете настроить сам ресурс изображения для рендеринга в режиме шаблона. После этого вы можете установить tintColor кнопки в Интерфейсном Разработчике (или в коде), и это должно занять.

Ратнеш Н.С.
источник
3

Я нашел самый простой подход ниже,

Откройте каталог ресурсов и выберите изображение, затем перейдите в инспектор атрибутов и измените его Render Asна, Template Imageкак показано ниже.

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

Затем добавьте ниже код в метод действия кнопки

yourButton.tintColor = .gray
калпа
источник
-1

Swift 4 и 4.2

let img = UIImage.init(named: "buttonName")?.withRenderingMode(UIImageRenderingMode.alwaysTemplate)
            btn.setImage(img, for: .normal)
            btn.tintColor = .gray

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

Акбар Хан
источник