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


144

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

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

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


1
«Градиент» означает, что одна часть вашего изображения будет одного оттенка цвета, а другая часть будет более темным или более светлым оттенком. Это еще один способ определить, что вы хотите сделать?
Майкл Даутерманн

2
Взгляните на эту библиотеку github.com/yannickl/DynamicColor
onmyway133

Стремитесь, используя насыщенность оттенка и легкость stackoverflow.com/a/30012117/2303865
Лео Дабус

Ответы:


279
- (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, может быть, лучше сделать цвет пропорционально темнее или светлее, чем добавлять или вычитать постоянные значения. Как указал @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
Зачем использовать RGB, если вы можете сделать то же самое с оттенком, насыщенностью, яркостью, а затем просто перестроить цвет с измененной яркостью?
Джертонтон

2
Я сам пробовал версию HSB, и она не сработала так, как ожидалось. Несмотря на getHue:saturation:brightnessподпись UIKit, похоже, что он работает с HSV вместо HSB. Изменение яркости (так на самом деле значение) в этом контексте не будет работать. Например, чистый красный (rgb (255,0,0)) будет иметь яркость / значение 1, что делает невозможным освещение через яркость. Я закончил работать с изменениями значений RGB.
rchampourlier

2
Я думаю, что в вашем ответе есть что-то непонятное: вы используете два подхода (один с RGB, а другой с HSB для версии категории), которые не дают одинакового результата ... И это может быть вопросом значение: осветление действительно для меня, заставляя цвет стремиться к белому (затемнение к черному), в то время как изменение яркости / значения делает его сильнее (соответственно светлее).
rchampourlier

4
Эти методы потерпят неудачу, если они используются на оттенках серого. getHue:saturation:brightness:alphaвернет ЛОЖЬ.
Матье Риглер

2
Интересно, почему это принятый ответ, так как оба предложенных решения неверны ? Они оба просто меняют теоретические ценности, которые имеют мало общего с тем, что люди воспринимают как «более светлые» или «более темные» цвета. Я рекомендую прочесть этот замечательный пост (короткая ссылка: goo.gl/qqgk9V), чтобы понять, что я имею в виду. Это объясняет, что luminanceзначение цветового пространства LAB - это то, о чем вы должны заботиться, делая цвета светлее / темнее. Посмотрите мой ответ о том, как вы можете использовать его и правильно решить эту проблему.
Jeehut

59

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 приближает цвет к краю в шкале яркости - которая в основном начинается с черного и заканчивается чистым цветом ...

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

Как видно здесь:

Цветовой график HSV

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

- (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;
}

Что касается того, чтобы сделать цвета светлее: я получил лучший результат, уменьшив насыщенность и увеличив яркость / ценность. Этот ответ отлично подходит для цветов "сверху" пирога на изображении. Но большинство цветов упадет где-то «внутри» пирога. Для того, чтобы приблизить их к белому, необходимо также поднять их «вверх» (увеличение значения).
Пежало

Может показаться, что увеличение значения работает, но это не будет основной функцией «получить более светлый цвет». Точно так же, чтобы получить более темный цвет, правильным подходом было бы только уменьшить «Value» и оставить насыщенность такой, какая она есть ...
Aviel Gross

38

Swift универсальное расширение для 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()

Образец :

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


Я получил ошибку: -getHue: насыщенность: яркость: альфа: недопустимо для NSColor NSCalibratedWhiteColorSpace 0 1; нужно сначала конвертировать цветовое пространство.
Беси

2
Исправьте это, добавив: let color = usingColorSpaceName(NSCalibratedRGBColorSpace) и затем заменив getHueвызов на цветной вызов:color?.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha)
Оскар

Функция пропускает _перед словом количество. Должно бытьprivate func hueColorWithBrightnessAmount(_ amount: CGFloat) -> PXColor {
Codemonk

Я предлагаю добавить предложение @Oskar к ответу. Это исправило ошибку во время выполнения для меня.
Беси

29

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

  • поместив цвет с альфа х% на белом фоне, чтобы осветлить
  • поместив цвет с альфа х% на черном фоне, чтобы затемнить

Что дает тот же результат, AFAIK, что и выбор цвета с градиентом «цвет к белому» или «цвет к черному» при x% от размера градиента.

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

extension UIColor {
    func mix(with color: UIColor, amount: CGFloat) -> UIColor {
        var red1: CGFloat = 0
        var green1: CGFloat = 0
        var blue1: CGFloat = 0
        var alpha1: CGFloat = 0

        var red2: CGFloat = 0
        var green2: CGFloat = 0
        var blue2: CGFloat = 0
        var alpha2: CGFloat = 0

        getRed(&red1, green: &green1, blue: &blue1, alpha: &alpha1)
        color.getRed(&red2, green: &green2, blue: &blue2, alpha: &alpha2)

        return UIColor(
            red: red1 * (1.0 - amount) + red2 * amount,
            green: green1 * (1.0 - amount) + green2 * amount,
            blue: blue1 * (1.0 - amount) + blue2 * amount,
            alpha: alpha1
        )
    }
}

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

Примеры темнее и светлее


Я думаю, что это лучшая реализация, не прибегая к внешней библиотеке, которая реализует цветовое пространство HSL
gog

24

Решение 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()
}

1
Это хороший ответ, за исключением того, что было бы более удобно, если бы он был объявлен как расширение класса UIColor просто как, var darker: UIColorнапример.
Бруно Филипп

13

Если вы преобразуете цвет RGB в цветовую модель HSL, вы можете изменить компонент L = lightness от L = 0.0 (черный) до L = 0.5 (естественный цвет) до L = 1.0 (белый). UIColorне может обрабатывать HSL напрямую, но есть формула для преобразования RGB <-> HSL.



8
Различие между цветовой моделью HSL и HSB (иногда также называемой HSV) состоит в том, что в HSB L = 1.0 соответствует чистому цвету, тогда как в HSL L = 1.0 соответствует белому, а L = 0.5 - чистому цвету. Поскольку в оригинальном плакате спрашивалось, например, о способе сделать синий цвет (RGB = 0/0/1) более светлым, я думаю, что HSL более гибок.
Мартин Р

6

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

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


5

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()

2

Если вы хотите, чтобы решение 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.


2

UIColor расширение и фиксация легчеColorForColor

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

2

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


К сожалению, довольно сложно изменить любой из атрибутов UIColor по умолчанию . Кроме того, Apple даже не поддерживает какое-либо цветовое пространство на UIColorоснове LLAB, такое как HCL, в классе (значение в 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 .

Я надеюсь, что это помогает!


Для своего приложения я рисую маршруты на картах. Я хотел нарисовать маршрут с внутренней линией цвета с яркостью 100% и границей с более темным вариантом этого цвета. Поскольку внутренняя линия уже имела яркость 100%, ни один из методов не работал. Также изменение яркости, как упомянуто выше, не помогло. Тем не менее, уменьшение яркости с помощью этого замечательного расширения помогло мне. 'color.change (.brightness, by: -0.5)' Это расширение очень гибкое в использовании и имеет множество опций. Я рекомендую, особенно если у вас есть приложение с несколькими темами или цветовой палитрой.
Гвидо

1

Я не уверен, что вы ищете какой-то ответ 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];

Вуаля. Или, может быть, у вас есть апельсин:

[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];

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


Да, это половина того, что мне нужно. Есть ли способ получить более светлый цвет, когда синий равен 1 (Макс)
CoreCode

@CoreCode нет, не совсем. Если вы не хотите изменить цвет экрана устройства :) Смотрите мой ответ.

1

Протестировано в 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.


1

Swift 5

extension UIColor {

func lighter(by percentage:CGFloat=30.0) -> UIColor? {
    return self.adjust(by: abs(percentage) )
}

func darker(by percentage:CGFloat=30.0) -> UIColor? {
    return self.adjust(by: -1 * abs(percentage) )
}
func adjust(by percentage:CGFloat=30.0) -> 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 + percentage/100, 1.0),
                       green: min(g + percentage/100, 1.0),
                       blue: min(b + percentage/100, 1.0),
                       alpha: a)
    }else{
        return nil


     }
    }
}

0

В идеале, функции должны быть инкапсулированы внутри 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()
  }

}

0

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

статус-изображения

Для этого я написал быстрое расширение, основанное на некотором старом 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.


0

Вот категория 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;
}

0

Расширение Swift, основанное на ответе @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()
    }
}

-1

для более темного цвета это самое простое: theColor = [theColor shadowWithLevel: s]; //s:0.0 до 1.0


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