从UIColor中获得较浅和较深的颜色


144

我一直希望能够将任何UIColor变成渐变。我打算这样做的方法是使用Core Graphics绘制渐变。我想做的就是获得一种颜色,让我们说:

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

并获得一个UIColor,它的阴影要深一些,而阴影要浅一些。有谁知道如何做到这一点?谢谢。


1
“渐变”表示图像的一部分将是颜色的一种阴影,而另一部分将是更深或更浅的阴影。这是定义您想要做什么的另一种方法吗?
Michael Dautermann


快速使用色相饱和度和亮度stackoverflow.com/a/30012117/2303865
Leo Dabus,

Answers:


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?
jrturton 2012年

2
我本人一直在尝试使用HSB版本,但未按预期工作。尽管getHue:saturation:brightness有UIKit 的签名,但似乎它可以与HSV而不是HSB一起使用。在这种情况下更改亮度(实际上是该值)将不起作用。例如,纯红色(rgb(255,0,0))的亮度/值为1​​,因此无法通过该亮度进行照明。我最终改为使用RGB值进行更改。
rchampourlier

2
我认为您的答案有些令人困惑:您采用两种方法(一种使用RGB,另一种使用HSB的类别版本),结果却不一样……这可能是一个问题含义:对我而言,确实是变亮是使颜色趋于白色(变暗为黑色),而改变亮度/值则使颜色更强(分别是较亮)。
rchampourlier 2013年

4
如果将它们用于灰色阴影,则此方法将失败。getHue:saturation:brightness:alpha将返回FALSE。
Matthieu Riegler

2
我不知道为什么这是可接受的答案,因为两个建议的解决方案都不正确。它们都只是改变了与人类认为“较浅”或“较暗”的颜色无关的理论值。我建议阅读这篇精彩的文章(shortlink:goo.gl/qqgk9V)以了解我的意思。它说明luminance了LAB颜色空间价值是使颜色更浅/更暗时应注意的真正问题。请参阅我的答案了解如何使用它并以正确的方式解决此问题。
Jeehut

59

TL; DR:

迅速:

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

目标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颜色图

因此,使颜色实际上更亮(即更接近白色...)的解决方案将是使其饱和度值更小,从而得出以下解决方案:

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

关于使颜色更浅:通过降低饱和度并增加亮度/值,我获得了最佳效果。此答案非常适用于图像中“顶部”的颜色。但是大多数颜色将落在馅饼的“内部”。使它们更接近白色还需要将它们“向上”移动(价值增加)。
pejalo '16

增值看似可行,但不是“获得较浅颜色”的“核心”功能。同样,要获得较深的颜色,正确的方法是仅减少“值”,并保持饱和度
不变

38

适用于iOS和OS X的Swift通用扩展,使用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:saturation:brightness:alpha:不适用于NSColor NSCalibratedWhiteColorSpace 0 1; 需要先转换色彩空间。
Besi

2
通过添加:进行修复 let color = usingColorSpaceName(NSCalibratedRGBColorSpace) ,然后将getHue调用替换为对颜色的调用:color?.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha)
Oskar

该函数_在单词数量前缺少a 。应该是private func hueColorWithBrightnessAmount(_ amount: CGFloat) -> PXColor {
Codemonk

我建议在答案中添加@Oskar的建议。这确实为我解决了运行时崩溃。
Besi

29

我只是想在RGB中给出相同的结果

  • 将带有alpha x%的颜色放置在白色背景上以使其变亮
  • 将带有alpha x%的颜色放在黑色背景上变暗

与以渐变大小的x%从“从颜色到白色”或“从颜色到黑色”的渐变中选择颜色相比,这提供了相同的结果AFAIK。

为此,数学很简单:

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

Swift中user529758的解决方案:

深色:

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 =亮度分量从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更灵活。
Martin R

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:alphafalse在灰色阴影上调用时失败(并返回),因此您需要使用getWhite:alpha


2

UIColor扩展和更正lighterColorForColor

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甚至不支持此类中的任何基于LAB的色彩空间(例如HCL)(在LAB中是我们正在寻找的值)。UIColorLluminance

使用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还向您的项目中添加了一些其他方便的UI功能在GitHub上查看其README了解更多详细信息。

希望对您有所帮助!


对于我的应用程序,我在地图上绘制路线。我想用内部亮度为100%的颜色绘制线条,并使用该颜色的较深变体绘制边框。由于内线已经具有100%的亮度,因此所有方法均无效。同样如上所述改变亮度并不能解决问题。但是,使用此非常好的扩展程序来降低亮度对我来说是成功的窍门。'color.change(.brightness,by:-0.5)'此扩展名在使用中非常灵活,并且有很多选择。我建议,如果您的应用程序具有多个主题或调色板,则尤其如此。
guido

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

在iOS 12的Swift 4.x中通过Xcode 10测试

从您的颜色作为UIColor开始,然后选择一个变暗的因子(作为CGFloat)

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

CGColor类型具有一个可选值components,该值将颜色分解为RGBA(作为CGFloat数组,其值在0到1之间)。然后,您可以使用从CGColor中获取的RGBA值来重建UIColor并对其进行操作。

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除以使颜色变暗为以前的一半。Alpha值保持不变,但是您也可以在Alpha值而不是RGB上应用变暗因子。


1

斯威夫特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

我根据状态值渲染彩色单元格:

状态图像

为此,在使用CryingHippo的建议出错时,我基于一些旧的objc代码编写了一个快速扩展:

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。只需替换UIColorNSColor


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

基于@Sebyddd答案的Swift扩展:

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.