Получите чуть светлее и темнее цвет от UIColor

Я искал возможность превратить любой UIColor в градиент. Способ, которым я намереваюсь это сделать, - использовать Core Graphics для рисования градиента. Я пытаюсь получить цвет, скажем:

[UIColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:1.0];

и получите UIColor, который несколько оттенков темнее и несколько оттенков светлее. Кто-нибудь знает как это сделать? Спасибо.

Ответ 1

- (UIColor *)lighterColorForColor:(UIColor *)c
{
    CGFloat r, g, b, a;
    if ([c getRed:&r green:&g blue:&b alpha:&a])
        return [UIColor colorWithRed:MIN(r + 0.2, 1.0)
                               green:MIN(g + 0.2, 1.0)
                                blue:MIN(b + 0.2, 1.0)
                               alpha:a];
    return nil;
}

- (UIColor *)darkerColorForColor:(UIColor *)c
{
    CGFloat r, g, b, a;
    if ([c getRed:&r green:&g blue:&b alpha:&a])
        return [UIColor colorWithRed:MAX(r - 0.2, 0.0)
                               green:MAX(g - 0.2, 0.0)
                                blue:MAX(b - 0.2, 0.0)
                               alpha:a];
    return nil;
}

Используйте его следующим образом:

UIColor *baseColor = // however you obtain your color
UIColor *lighterColor = [self lighterColorForColor:baseColor];
UIColor *darkerColor = [self darkerColorForColor:baseColor];

РЕДАКТИРОВАТЬ: как указал @Anchu Chimala, для максимальной гибкости эти методы должны быть реализованы как категория UIColor. Кроме того, из идеи @Riley, может быть, лучшая идея сделать цвет proprtionally темнее или легче, вместо добавления или вычитания постоянных значений. Как отметил @jrturton, нет необходимости манипулировать компонентами RGB; лучше изменить свойство яркости. Всего:

@implementation UIColor (LightAndDark)

- (UIColor *)lighterColor
{
    CGFloat h, s, b, a;
    if ([self getHue:&h saturation:&s brightness:&b alpha:&a])
        return [UIColor colorWithHue:h
                          saturation:s
                          brightness:MIN(b * 1.3, 1.0)
                               alpha:a];
    return nil;
}

- (UIColor *)darkerColor
{
    CGFloat h, s, b, a;
    if ([self getHue:&h saturation:&s brightness:&b alpha:&a])
        return [UIColor colorWithHue:h
                          saturation:s
                          brightness:b * 0.75
                               alpha:a];
    return nil;
}
@end

Ответ 2

TL; DR:

Swift:

extension UIColor {

    var lighterColor: UIColor {
        return lighterColor(removeSaturation: 0.5, resultAlpha: -1)
    }

    func lighterColor(removeSaturation val: CGFloat, resultAlpha alpha: CGFloat) -> UIColor {
        var h: CGFloat = 0, s: CGFloat = 0
        var b: CGFloat = 0, a: CGFloat = 0

        guard getHue(&h, saturation: &s, brightness: &b, alpha: &a)
            else {return self}

        return UIColor(hue: h,
                       saturation: max(s - val, 0.0),
                       brightness: b,
                       alpha: alpha == -1 ? a : alpha)
    }
}

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

let lightColor = somethingDark.lighterColor

Objective-C:

- (UIColor *)lighterColorRemoveSaturation:(CGFloat)removeS
                              resultAlpha:(CGFloat)alpha {
    CGFloat h,s,b,a;
    if ([self getHue:&h saturation:&s brightness:&b alpha:&a]) {
        return [UIColor colorWithHue:h
                          saturation:MAX(s - removeS, 0.0)
                          brightness:b
                               alpha:alpha == -1? a:alpha];
    }
    return nil;
}

- (UIColor *)lighterColor {
    return [self lighterColorRemoveSaturation:0.5
                                  resultAlpha:-1];
}

@rchampourlier был прав в своем комментарии к @user529758 (принятый ответ) - решения HSB (или HSV) и RGB дают совершенно разные результаты. RGB просто добавляет (или приближает цвет ближе) к белому, а решение HSB приближает цвет к краю в шкале Brigtness, который в основном начинается с черного и заканчивается чистым цветом...

В основном яркость (значение) делает цвет меньше или ближе к черному, где насыщенность делает его менее или более близким к белому...

Как показано здесь:

HSV color graph

Таким образом, решение сделать цвет на самом деле ярче (то есть ближе к белому...) будет сделать его значение насыщенности меньше, в результате получим это решение:

- (UIColor *)lighterColor {
    CGFloat h,s,b,a;
    if ([self getHue:&h saturation:&s brightness:&b alpha:&a]) {
        return [UIColor colorWithHue:h
                          saturation:MAX(s - 0.3, 0.0)
                          brightness:b /*MIN(b * 1.3, 1.0)*/
                               alpha:a];
    }
    return nil;
}

Ответ 3

Быстрое универсальное расширение для iOS и OS X, используя getHue:

#if os(OSX)

    import Cocoa
    public  typealias PXColor = NSColor

    #else

    import UIKit
    public  typealias PXColor = UIColor

#endif

    extension PXColor {

    func lighter(amount : CGFloat = 0.25) -> PXColor {
        return hueColorWithBrightnessAmount(1 + amount)
    }

    func darker(amount : CGFloat = 0.25) -> PXColor {
        return hueColorWithBrightnessAmount(1 - amount)
    }

    private func hueColorWithBrightnessAmount(amount: CGFloat) -> PXColor {
        var hue         : CGFloat = 0
        var saturation  : CGFloat = 0
        var brightness  : CGFloat = 0
        var alpha       : CGFloat = 0

        #if os(iOS)

            if getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha) {
                return PXColor( hue: hue,
                                saturation: saturation,
                                brightness: brightness * amount,
                                alpha: alpha )
            } else {
                return self
            }

            #else

            getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha)
            return PXColor( hue: hue,
                            saturation: saturation,
                            brightness: brightness * amount,
                            alpha: alpha )

        #endif

    }

}

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

let color = UIColor(red: 0.5, green: 0.8, blue: 0.8, alpha: 1.0)
color.lighter(amount:0.5)
color.darker(amount:0.5)

ИЛИ (со значениями по умолчанию):

color.lighter()
color.darker()

Пример:

enter image description here

Ответ 4

user529758 решение в Swift:

Темный цвет:

func darkerColorForColor(color: UIColor) -> UIColor {

       var r:CGFloat = 0, g:CGFloat = 0, b:CGFloat = 0, a:CGFloat = 0

       if color.getRed(&r, green: &g, blue: &b, alpha: &a){
           return UIColor(red: max(r - 0.2, 0.0), green: max(g - 0.2, 0.0), blue: max(b - 0.2, 0.0), alpha: a)
       }

       return UIColor()
}

Более светлый цвет:

func lighterColorForColor(color: UIColor) -> UIColor {

       var r:CGFloat = 0, g:CGFloat = 0, b:CGFloat = 0, a:CGFloat = 0

       if color.getRed(&r, green: &g, blue: &b, alpha: &a){
           return UIColor(red: min(r + 0.2, 1.0), green: min(g + 0.2, 1.0), blue: min(b + 0.2, 1.0), alpha: a)
       }

       return UIColor()
}

Ответ 5

Я просто хотел дать тот же результат в RGB, чем

  • размещение цвета с альфа-х% на белом фоне для облегчения
  • поместив цвет с альфа-x% на черный фон, чтобы затемнить

Это дает тот же результат, что и AFAIK, чем выбор цвета в градиенте "цвет в белый" или "цвет в черный" при x% от размера градиента.

Для этого математика проста:

// UIColor+Mix.swift
import UIKit
extension UIColor {

    func mixLighter (amount: CGFloat = 0.25) -> UIColor {
        return mixWithColor(UIColor.whiteColor(), amount:amount)
    }

    func mixDarker (amount: CGFloat = 0.25) -> UIColor {
        return mixWithColor(UIColor.blackColor(), amount:amount)
    }

    func mixWithColor(color: UIColor, amount: CGFloat = 0.25) -> UIColor {
        var r1     : CGFloat = 0
        var g1     : CGFloat = 0
        var b1     : CGFloat = 0
        var alpha1 : CGFloat = 0
        var r2     : CGFloat = 0
        var g2     : CGFloat = 0
        var b2     : CGFloat = 0
        var alpha2 : CGFloat = 0

        self.getRed (&r1, green: &g1, blue: &b1, alpha: &alpha1)
        color.getRed(&r2, green: &g2, blue: &b2, alpha: &alpha2)
        return UIColor( red:r1*(1.0-amount)+r2*amount,
                        green:g1*(1.0-amount)+g2*amount,
                        blue:b1*(1.0-amount)+b2*amount,
                        alpha: alpha1 )
    }
}

Вот примеры с некоторыми цветами

Examples Darker and Lighter

Ответ 6

Если вы преобразуете цвет RGB в цветную модель HSL, тогда вы можете изменить компонент L = lightness от L = 0.0 (черный) по L = 0,5 (естественный цвет) до L = 1,0 (белый). UIColor не может обрабатывать HSL напрямую, но есть формула для преобразования RGB ↔ HSL.

Ответ 7

Ни одно из выпущенных решений не работало для всех цветов и оттенков, но затем я наткнулся на эту библиотеку, которая предоставляет набор очень хорошо реализованных расширения для UIColor.

В частности, он имеет функцию lighten как часть реализации HSL: (UIColor *)lighten:(CGFloat)amount - который отлично работает.

Ответ 8

Если вы хотите, чтобы решение user529758 работало с серыми оттенками (например, [UIColor lightGrayColor] или [UIColor darkGrayColor], вам нужно улучшить его так:

- (UIColor *)lighterColor
{
    CGFloat h, s, b, a;
    if ([self getHue:&h saturation:&s brightness:&b alpha:&a]) {
        return [UIColor colorWithHue:h
                          saturation:s
                          brightness:MIN(b * 1.3, 1.0)
                               alpha:a];
    }

    CGFloat white, alpha;
    if ([self getWhite:&white alpha:&alpha]) {
        white = MIN(1.3*white, 1.0);
        return [UIColor colorWithWhite:white alpha:alpha];
    }

    return nil;
}

getHue:saturation:brightness:alpha не работает (и возвращает false) при вызове в оттенке серого, поэтому вам нужно использовать getWhite:alpha.

Ответ 9

Расширение и фиксация UIColorColorForColor

extension UIColor {
  class func darkerColorForColor(color: UIColor) -> UIColor {
    var r:CGFloat = 0, g:CGFloat = 0, b:CGFloat = 0, a:CGFloat = 0
    if color.getRed(&r, green: &g, blue: &b, alpha: &a){
      return UIColor(red: max(r - 0.2, 0.0), green: max(g - 0.2, 0.0), blue: max(b - 0.2, 0.0), alpha: a)
    }
    return UIColor()
  }

  class func lighterColorForColor(color: UIColor) -> UIColor {
    var r:CGFloat = 0, g:CGFloat = 0, b:CGFloat = 0, a:CGFloat = 0
    if color.getRed(&r, green: &g, blue: &b, alpha: &a){
      let tmpColor = UIColor(red: min(r + 0.2, 1.0), green: min(g + 0.2, 1.0), blue: min(b + 0.2, 1.0), alpha: a)
      println(tmpColor)
      return tmpColor
    }
    return UIColor()
  }
}

Ответ 10

Sebyddd решение как расширение:

extension UIColor {    
    func darker() -> UIColor {

        var r:CGFloat = 0, g:CGFloat = 0, b:CGFloat = 0, a:CGFloat = 0

        if self.getRed(&r, green: &g, blue: &b, alpha: &a){
            return UIColor(red: max(r - 0.2, 0.0), green: max(g - 0.2, 0.0), blue: max(b - 0.2, 0.0), alpha: a)
        }

        return UIColor()
    }

    func lighter() -> UIColor {

        var r:CGFloat = 0, g:CGFloat = 0, b:CGFloat = 0, a:CGFloat = 0

        if self.getRed(&r, green: &g, blue: &b, alpha: &a){
            return UIColor(red: min(r + 0.2, 1.0), green: min(g + 0.2, 1.0), blue: min(b + 0.2, 1.0), alpha: a)
        }

        return UIColor()
    }
}

Применение:

let darkerYellow = UIColor.yellow.darker()
let lighterYellow = UIColor.yellow.lighter()

Ответ 11

Я не уверен, что вы ищете какой-то ответ Objective-C, но в зависимости от того, как работают цвета, заданные RGBA, я думаю, вы можете просто масштабировать значения RGB в соответствии с произвольным коэффициентом, чтобы получить "светлее" или "темнее". Например, у вас может быть синий цвет:

[UIColor colorWithRed:0.0 green:0.0 blue:1.0 alpha:1.0];

Хотите темно-синий? Умножьте значения RGB на 0,9:

[UIColor colorWithRed:0.0 green:0.0 blue:0.9 alpha:1.0];

Voila. Или, может быть, у вас оранжевый:

[UIColor colorWithRed:1.0 green:0.4 blue:0.0 alpha:1.0];

Выберите другой масштабный коэффициент, скажем, 0,8:

[UIColor colorWithRed:0.8 green:0.32 blue:0.0 alpha:1.0];

Это тот вид эффекта, который вы ищете?

Ответ 12

Все остальные ответы в этом потоке используют цветную систему RGB или просто изменяют значение оттенка или яркости системы HSB. Как подробно объяснено в это отличное сообщение в блоге, правильный способ сделать цвет светлее или темнее - изменить его luminance значение. Ни один из других ответов не делает этого. Если вы хотите сделать это правильно, использовать мое решение или написать свой собственный после прочтения сообщения в блоге.


К сожалению, он довольно хлопот, чтобы поменять любой из атрибутов UIColor по умолчанию. Также Apple даже не поддерживает любое цветовое пространство LAB, такое как HCL в классе UIColor (L в LAB - это значение luminance, которое мы ищем).

Использование HandyUIKit (установить его через Carthage) добавляет поддержку HCL и делает вашу жизнь намного проще:

import HandyUIKit    

let color = UIColor(red: 0.5, green: 0.5, blue: 0.5, alpha: 1.0)

// create a new UIColor object with a specific luminance (slightly lighter)
color.change(.luminance, to: 0.7)

Существует также возможность применить относительное изменение (рекомендуется):

// create a new UIColor object with slightly darker color
color.change(.luminance, by: -0.2)

Обратите внимание, что HandyUIKit также добавляет некоторые другие удобные функции пользовательского интерфейса в ваш проект - вытащите его README на GitHub для более подробная информация.

Надеюсь, это поможет!

Ответ 13

В идеале функции должны инкапсулироваться внутри расширения UIColor, называемого UIColor+Brightness.swift, и иметь настраиваемую яркость - см. пример ниже:

import UIKit

extension UIColor {

  func lighterColorWithBrightnessFactor(brightnessFactor:CGFloat) -> UIColor {
    var r:CGFloat = 0, g:CGFloat = 0, b:CGFloat = 0, a:CGFloat = 0
    if self.getRed(&r, green:&g, blue:&b, alpha:&a) {
      return UIColor(red:min(r + brightnessFactor, 1.0),
        green:min(g + brightnessFactor, 1.0),
        blue:min(b + brightnessFactor, 1.0),
        alpha:a)
    }
    return UIColor()
  }

}

Ответ 14

Я отображаю цветные ячейки на основе значения состояния:

status-images

Для этого я написал быстрое расширение, основанное на каком-то старом коде objc после того, как я получил ошибку, используя предложение CryingHippo:

extension UIColor{

    func darker(darker: CGFloat) -> UIColor{

        var red: CGFloat = 0.0
        var green: CGFloat = 0.0
        var blue: CGFloat = 0.0

        if self.colorSpace == UIColorSpace.genericGrayColorSpace(){

            red =  whiteComponent - darker
            green = whiteComponent - darker
            blue  = whiteComponent - darker
        } else {
            red = redComponent - darker
            green = greenComponent - darker
            blue = blueComponent - darker
        }

        if red < 0{
            green += red/2
            blue += red/2
        }

        if green < 0{
            red += green/2
            blue += green/2
        }

        if blue < 0{
            green += blue/2
            red += blue/2
        }

        return UIColor(
            calibratedRed: red,
            green: green,
            blue: blue,
            alpha: alphaComponent
        )
    }

    func lighter(lighter: CGFloat) -> UIColor{
        return darker(-lighter)
    }
}

То же самое работает и для NSColor. Просто замените UIColor на NSColor.

Ответ 15

Вот категория UIColor, которая также позволяет контролировать количество изменений цвета.

- (UIColor *)lighterColorWithDelta:(CGFloat)delta
{
    CGFloat r, g, b, a;
    if ([self getRed:&r green:&g blue:&b alpha:&a])
        return [UIColor colorWithRed:MIN(r + delta, 1.0)
                               green:MIN(g + delta, 1.0)
                                blue:MIN(b + delta, 1.0)
                               alpha:a];
    return nil;
}

- (UIColor *)darkerColorWithDelta:(CGFloat)delta
{
    CGFloat r, g, b, a;
    if ([self getRed:&r green:&g blue:&b alpha:&a])
        return [UIColor colorWithRed:MAX(r - delta, 0.0)
                               green:MAX(g - delta, 0.0)
                                blue:MAX(b - delta, 0.0)
                               alpha:a];
    return nil;
}

Ответ 16

Быстрое расширение, основанное на ответе @Sebyddd:

import Foundation
import UIKit

extension UIColor{
    func colorWith(brightness: CGFloat) -> UIColor{
        var r:CGFloat = 0, g:CGFloat = 0, b:CGFloat = 0, a:CGFloat = 0

        if getRed(&r, green: &g, blue: &b, alpha: &a){
            return UIColor(red: max(r + brightness, 0.0), green: max(g + brightness, 0.0), blue: max(b + brightness, 0.0), alpha: a)
        }

        return UIColor()
    }
}

Ответ 17

Протестировано в Xcode 10 с Swift 4.x для iOS 12

Начните с вашего цвета как UIColor и выберите коэффициент затемнения (как CGFloat)

let baseColor = UIColor.red
let darkenFactor: CGFloat = 2

Тип CGColor имеет необязательные components значения, которые разбивают цвет на RGBA (как массив CGFloat со значениями от 0 до 1). Затем вы можете восстановить UIColor, используя значения RGBA, взятые из CGColor, и манипулировать ими.

let darkenedBase = UIColor(displayP3Red: startColor.cgColor.components![0] / darkenFactor, green: startColor.cgColor.components![1] / darkenFactor, blue: startColor.cgColor.components![2] / darkenFactor, alpha: 1)

В этом примере каждый из значений RGB был разделен на 2, делая цвет наполовину темным, как и раньше. Значение альфа оставалось неизменным, но вы могли альтернативно применять темный фактор на альфа-значение, а не на RGB.