获取给定UIColor的较浅和较深的颜色变化


69

如何在Swift中获得给定UIColor的不同的明暗变化?

在此处输入图片说明


1
标题问题非常琐碎,可以有不同的解决方案;你也可以使用负的输入参数用一个函数而不是两个
阴影

在这里stackoverflow.com/questions/11598043/…提出了各种技术,在Swift中也有答案。
Martin R

@ShadowOf已更新,感谢您的输入
斯蒂芬

迅捷
-4.0

在您发布问题时,此答案已经可用。总的来说,我认为这个问题与其他问题非常相似,即使没有重复。
gog

Answers:


146

更新

在下面的UIColor扩展中使用

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 red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0, alpha: CGFloat = 0
        if self.getRed(&red, green: &green, blue: &blue, alpha: &alpha) {
            return UIColor(red: min(red + percentage/100, 1.0),
                           green: min(green + percentage/100, 1.0),
                           blue: min(blue + percentage/100, 1.0),
                           alpha: alpha)
        } else {
            return nil
        }
    }
}

用法:

let color = UIColor(red:0.96, green:0.54, blue:0.10, alpha:1.0)
color.lighter(30) // returns lighter color by 30%
color.darker(30) // returns darker color by 30%

代替.lighter().darker(),可以将.adjust()正值用于加亮,将负值用于加深

color.adjust(-30) // 30% darker color
color.adjust(30) // 30% lighter color

输出:

在此处输入图片说明


3
您可以用相同的值修改所有组件,而不是按比例更改它们。使其变浅时,看看橙色如何变成黄色。
Martin R

按比例添加值是不正确的。尝试使用此颜色UIColor(红色:0.89,绿色:0.28,蓝色:0.00,阿尔法:1.0)
史蒂芬·史蒂芬(Stephen

4
但是向所有组件添加相同的值也不正确,它会更改颜色。看一下stackoverflow.com/questions/11598043/…的各种答案, 在这里可以调整HSB表示中的亮度
Martin R

@MartinR我已经执行了我的函数,我的函数执行了,两个输出都相同(橙色没有变成黄色;-))。但是我需要提高技巧以减少代码。我应该避免转换为RGB值并在单个函数中写入逻辑。将会更新代码
Stephen

我相信黑色打火机会返回绿色
NNikN

41

我想提供使用亮度和饱和度而不是RGB的另一个版本

extension UIColor {
  /**
   Create a ligher color
   */
  func lighter(by percentage: CGFloat = 30.0) -> UIColor {
    return self.adjustBrightness(by: abs(percentage))
  }

  /**
   Create a darker color
   */
  func darker(by percentage: CGFloat = 30.0) -> UIColor {
    return self.adjustBrightness(by: -abs(percentage))
  }

  /**
   Try to increase brightness or decrease saturation
   */
  func adjustBrightness(by percentage: CGFloat = 30.0) -> UIColor {
    var h: CGFloat = 0, s: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
    if self.getHue(&h, saturation: &s, brightness: &b, alpha: &a) {
      if b < 1.0 {
        let newB: CGFloat = max(min(b + (percentage/100.0)*b, 1.0), 0.0)
        return UIColor(hue: h, saturation: s, brightness: newB, alpha: a)
      } else {
        let newS: CGFloat = min(max(s - (percentage/100.0)*s, 0.0), 1.0)
        return UIColor(hue: h, saturation: newS, brightness: b, alpha: a)
      }
    }
    return self
  }
}

4
我认为这比修改RGB值更好
Mihai Fratu

当饱和度为0且亮度为1.0时,请不要认为这可行。IE白色。在这种情况下,您的饱和度不变。
lostintranslation

(您不能使白色变亮。)这是正确的方法。RGB答案在许多级别上都是完全错误的。
Fattie

8

为了节省任何人键入的时间,简单实用的版本只是

extension UIColor {

    var darker: UIColor {

    var h: CGFloat = 0, s: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0

        guard self.getHue(&h, saturation: &s, brightness: &b, alpha: &a) else {
            print("** some problem demuxing the color")
            return .gray
        }

        let nudged = b * 0.5

        return UIColor(hue: h, saturation: s, brightness: nudged, alpha: a)
    }
}

使用像

something.color = .yellow.darker

要么

backgroundColor = backgroundColor.darker

在大型项目中.................

您绝对应该扩展Apple的模式:

.withAlphaComponent(_ alpha: CGFloat)

因此,有:

.withBrightnessComponent(_ alpha: CGFloat)

并且明显地

.withBrightnessComponentAdjustedBy(percentage: CGFloat)

和/或

.withBrightnessComponentMultipliedBy(factor: CGFloat)

6

SwiftUI:颜色-iOS 14 / macOS 10.16

extension Color {
    public func lighter(by amount: CGFloat = 0.2) -> Self { Self(UIColor(self).lighter(by: amount)) }
    public func darker(by amount: CGFloat = 0.2) -> Self { Self(UIColor(self).darker(by: amount)) }
}

需要iOS或(和)macOS的以下一项(或两项)


AppKit:NSColor

extension NSColor {
    func mix(with color: NSColor, amount: CGFloat) -> Self {
        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 Self(
            red: red1 * CGFloat(1.0 - amount) + red2 * amount,
            green: green1 * CGFloat(1.0 - amount) + green2 * amount,
            blue: blue1 * CGFloat(1.0 - amount) + blue2 * amount,
            alpha: alpha1
        )
    }

    func lighter(by amount: CGFloat = 0.2) -> Self { mix(with: .white, amount: amount) }
    func darker(by amount: CGFloat = 0.2) -> Self { mix(with: .black, amount: amount) }
}

UIKit:UIColor

extension UIColor {
    func mix(with color: UIColor, amount: CGFloat) -> Self {
        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 Self(
            red: red1 * CGFloat(1.0 - amount) + red2 * amount,
            green: green1 * CGFloat(1.0 - amount) + green2 * amount,
            blue: blue1 * CGFloat(1.0 - amount) + blue2 * amount,
            alpha: alpha1
        )
    }

    func lighter(by amount: CGFloat = 0.2) -> Self { mix(with: .white, amount: amount) }
    func darker(by amount: CGFloat = 0.2) -> Self { mix(with: .black, amount: amount) }
}

Eivoullla Mojtaba!👏
Ahmadreza

4

对于Swift 5.0:

extension UIColor {

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

func darker(by percentage: CGFloat = 10.0) -> UIColor {
    return self.adjust(by: -abs(percentage))
}

func adjust(by percentage: CGFloat) -> UIColor {
    var alpha, hue, saturation, brightness, red, green, blue, white : CGFloat
    (alpha, hue, saturation, brightness, red, green, blue, white) = (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)

    let multiplier = percentage / 100.0

    if self.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha) {
        let newBrightness: CGFloat = max(min(brightness + multiplier*brightness, 1.0), 0.0)
        return UIColor(hue: hue, saturation: saturation, brightness: newBrightness, alpha: alpha)
    }
    else if self.getRed(&red, green: &green, blue: &blue, alpha: &alpha) {
        let newRed: CGFloat = min(max(red + multiplier*red, 0.0), 1.0)
        let newGreen: CGFloat = min(max(green + multiplier*green, 0.0), 1.0)
        let newBlue: CGFloat = min(max(blue + multiplier*blue, 0.0), 1.0)
        return UIColor(red: newRed, green: newGreen, blue: newBlue, alpha: alpha)
    }
    else if self.getWhite(&white, alpha: &alpha) {
        let newWhite: CGFloat = (white + multiplier*white)
        return UIColor(white: newWhite, alpha: alpha)
    }

    return self
    }
}

3

由于我在当前项目中使用SwiftUI,因此我改编了Stephen的最佳答案。经过Xcode 12.0,SwiftUI 2和iOS 14.0的测试

extension Color {
    var components: (red: CGFloat, green: CGFloat, blue: CGFloat, opacity: CGFloat) {
        #if canImport(UIKit)
        typealias NativeColor = UIColor
        #elseif canImport(AppKit)
        typealias NativeColor = NSColor
        #endif

        var r: CGFloat = 0
        var g: CGFloat = 0
        var b: CGFloat = 0
        var o: CGFloat = 0

        guard NativeColor(self).getRed(&r, green: &g, blue: &b, alpha: &o) else {
            return (0, 0, 0, 0)
        }
        return (r, g, b, o)
    }
    
    func lighter(by percentage: CGFloat = 30.0) -> Color {
        return self.adjust(by: abs(percentage) )
    }

    func darker(by percentage: CGFloat = 30.0) -> Color {
        return self.adjust(by: -1 * abs(percentage) )
    }

    func adjust(by percentage: CGFloat = 30.0) -> Color {
        return Color(red: min(Double(self.components.red + percentage/100), 1.0),
                     green: min(Double(self.components.green + percentage/100), 1.0),
                     blue: min(Double(self.components.blue + percentage/100), 1.0),
                     opacity: Double(self.components.opacity))
    }
}

2

具有RGB值修改的版本

在这里,我将UIColor基于前面的答案进行简单扩展。它对我来说很完美。

下面的演示:

颜色演示

颜色处理代码

public extension UIColor {

    /**
     Create a lighter color
     */
    public func lighter(by percentage: CGFloat = 30.0) -> UIColor {
        return self.adjustBrightness(by: abs(percentage))
    }

    /**
     Create a darker color
     */
    public func darker(by percentage: CGFloat = 30.0) -> UIColor {
        return self.adjustBrightness(by: -abs(percentage))
    }

    /**
     Changing R, G, B values
     */

    func adjustBrightness(by percentage: CGFloat = 30.0) -> UIColor {

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

        if self.getRed(&red, green: &green, blue: &blue, alpha: &alpha) {

            let pFactor = (100.0 + percentage) / 100.0

            let newRed = (red*pFactor).clamped(to: 0.0 ... 1.0)
            let newGreen = (green*pFactor).clamped(to: 0.0 ... 1.0)
            let newBlue = (blue*pFactor).clamped(to: 0.0 ... 1.0)

            return UIColor(red: newRed, green: newGreen, blue: newBlue, alpha: alpha)
        }

        return self
    }
}

固定功能 扩展,可轻松将值保持在最小值和最大值之间。

extension Comparable {

    func clamped(to range: ClosedRange<Self>) -> Self {

        if self > range.upperBound {
            return range.upperBound
        } else if self < range.lowerBound {
            return range.lowerBound
        } else {
            return self
        }
    }
}

1

只要您的起始颜色不是黑色(亮度值为0),Kenji-Tran的答案就可以正常工作。通过添加几行额外的代码,您还可以使黑色“更亮”(即将其变亮为灰度或颜色值)。

注意:由于我的“新男孩”代表,我无法使用“编辑”添加此更改,并且我也无法评论Kenji-Tran的答案,因此,我找不到其他方法可以分享我对SO的了解,发布新答案。我希望可以。

extension UIColor {
  /**
   Create a ligher color
   */
  func lighter(by percentage: CGFloat = 30.0) -> UIColor {
    return self.adjustBrightness(by: abs(percentage))
  }

  /**
   Create a darker color
   */
  func darker(by percentage: CGFloat = 30.0) -> UIColor {
    return self.adjustBrightness(by: -abs(percentage))
  }

  /**
   Try to increase brightness or decrease saturation
   */
  func adjustBrightness(by percentage: CGFloat = 30.0) -> UIColor {
    var h: CGFloat = 0, s: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
    if self.getHue(&h, saturation: &s, brightness: &b, alpha: &a) {
      if b < 1.0 {
        /**
         Below is the new part, which makes the code work with black as well as colors
        */
        let newB: CGFloat
        if b == 0.0 {
            newB = max(min(b + percentage/100, 1.0), 0.0)
        } else {
            newB = max(min(b + (percentage/100.0)*b, 1.0), 0,0)
        }
        return UIColor(hue: h, saturation: s, brightness: newB, alpha: a)
      } else {
        let newS: CGFloat = min(max(s - (percentage/100.0)*s, 0.0), 1.0)
        return UIColor(hue: h, saturation: newS, brightness: b, alpha: a)
      }
    }
    return self
  }
}

感谢您指出遗漏的案件(y)。我可以问个问题吗?为什么会这样b == 0.0 && s == 0.0呢?我以为只需要更多案例b == 0就足以解决问题。因为如果b is 0 and s > 0,您的代码仍然无法使颜色变得亮丽?
泉泉

好问题。错了 我已经修复了代码。我检查的原因s == 0是因为我希望它适用于黑色到灰度。但是很明显,如果没有,s == 0则它适用于亮度为零的任何颜色。谢谢。
ChrisDL

0

使用lukszar钳位函数,我使用RGB值的实际比例为UIColor扩展编写了此函数。希望对您有所帮助

public extension UIColor {

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

  public func darker(by percentage: CGFloat = 30.0) -> UIColor {
    return self.adjustBrightness(by: -abs(percentage))
  }

  func adjustBrightness(by percentage: CGFloat = 30.0) -> UIColor {

    let ratio = percentage/100

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

    if self.getRed(&red, green: &green, blue: &blue, alpha: &alpha) {
      let newRed =   (red   + ((ratio < 0) ? red   * ratio : (1 - red)   * ratio)).clamped(to: 0.0 ... 1.0)
      let newGreen = (green + ((ratio < 0) ? green * ratio : (1 - green) * ratio)).clamped(to: 0.0 ... 1.0)
      let newBlue =  (blue  + ((ratio < 0) ? blue  * ratio : (1 - blue)  * ratio)).clamped(to: 0.0 ... 1.0)
      return UIColor(red: newRed, green: newGreen, blue: newBlue, alpha: alpha)
    }
    return self
  }
}

0

在此处输入图片说明

下面的代码示例演示如何获得给定颜色的较浅和较深的阴影,在具有动态主题的应用程序中很有用

对于深色

+ (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)
return nil; 
}

对于较浅的颜色

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


0

支持RGBA,HSBA和WB(灰度)的Swift 4版本

这是TranQuan答案的一种变体,它还支持灰度颜色,例如.white.black。(注意:我删除了饱和度调整,因为我不认为它属于像这样的简单函数。)

extension UIColor {
    /**
     Create a ligher color
     */
    func lighter(by percentage: CGFloat = 10.0) -> UIColor {
        return self.adjustBrightness(by: abs(percentage))
    }

    /**
     Create a darker color
     */
    func darker(by percentage: CGFloat = 10.0) -> UIColor {
        return self.adjustBrightness(by: -abs(percentage))
    }

    /**
     Try to adjust brightness and falls back to adjusting colors if necessary
     */
    func adjustBrightness(by percentage: CGFloat) -> UIColor {
        var alpha, hue, saturation, brightness, red, green, blue, white : CGFloat
        (alpha, hue, saturation, brightness, red, green, blue, white) = (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)

        let multiplier = percentage / 100.0

        if self.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha) {
            let newBrightness: CGFloat = max(min(brightness + multiplier*brightness, 1.0), 0.0)
            return UIColor(hue: hue, saturation: saturation, brightness: newBrightness, alpha: alpha)
        }
        else if self.getRed(&red, green: &green, blue: &blue, alpha: &alpha) {
            let newRed: CGFloat = min(max(red + multiplier*red, 0.0), 1.0)
            let newGreen: CGFloat = min(max(green + multiplier*green, 0.0), 1.0)
            let newBlue: CGFloat = min(max(blue + multiplier*blue, 0.0), 1.0)
            return UIColor(red: newRed, green: newGreen, blue: newBlue, alpha: alpha)
        }
        else if self.getWhite(&white, alpha: &alpha) {
            let newWhite: CGFloat = (white + multiplier*white)
            return UIColor(white: newWhite, alpha: alpha)
        }

        return self
    }
}
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.