为给定的 UIColor 获取更亮和更暗的颜色变化

Posted

技术标签:

【中文标题】为给定的 UIColor 获取更亮和更暗的颜色变化【英文标题】:Get lighter and darker color variations for a given UIColor 【发布时间】:2016-11-20 23:27:59 【问题描述】:

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

【问题讨论】:

title 问题很简单,允许不同的解决方案;你也可以使用一个函数而不是两个使用负输入参数 这里***.com/questions/11598043/…提出了各种技术,Swift中也有答案。 @ShadowOf 已更新,感谢输入 Swift - 4.0 Click hare 回答 this answer 在您发布问题时已经可用。总的来说,我认为这个问题和其他问题非常相似,如果不重复的话。 【参考方案1】:

更新

使用下面的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

输出:

【讨论】:

您用相同的值修改所有组件,而不是按比例更改它们。看看当你把橙色调亮时,它是如何变成黄色的。 按比例添加值是不正确的。试试这个颜色 UIColor(red:0.89, green:0.28, blue:0.00, alpha:1.0) 但是向所有组件添加相同的值也不正确,它会改变颜色。查看***.com/questions/11598043/… 的各种答案,其中调整了 HSB 表示中的 brightness @MartinR 我已经执行了你的函数和我的函数,两个输出都是相同的(橙色没有变成黄色;-))。但是我需要提高技能以减少代码。我应该避免转换为 RGB 值并在单个函数中编写逻辑。将更新代码 我相信黑色打火机,返回绿色【参考方案2】:

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

extension UIColor 
  /**
   Create a lighter 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
  

【讨论】:

我觉得这比修改RGB值好 当饱和度为 0 且亮度为 1.0 时,不要认为这有效。即白色。在这种情况下,您最终会得到不变的饱和度。 (不能使白色变亮。)这是正确的方法。 RGB 的答案在很多层面上都是完全错误的。 但是你可以使白色变暗(它应该变成灰色)但这不会这样做:/【参考方案3】:

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

注意:我无法使用编辑添加此更改,并且由于我的“新男孩”代表,我无法评论 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 &amp;&amp; s == 0.0?我认为只需要更多案例b == 0 就足以解决问题。因为如果b is 0 and s &gt; 0,你的代码还是不能让颜色变浅? 好问题。这是一个错误。我已经修复了代码。我检查s == 0 的原因是因为我希望它适用于黑色到灰度。但显然,如果没有s == 0,它适用于任何亮度为零的颜色。谢谢。【参考方案4】:

修改 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
        
    

【讨论】:

【参考方案5】:

使用 lukszar 钳位函数,我为 UIColor 扩展编写了这个函数,使用 RGB 值的真实比例。希望对你有帮助

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
  

【讨论】:

【参考方案6】:

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

这是 TranQuan 的 answer 的一个变体,它也支持像 .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
    

【讨论】:

这很好用,谢谢! 我实际上似乎无法增亮.black 或真正的深灰色,因此作为一种解决方法,我创建了另一个函数,该函数采用百分比并将颜色的亮度直接设置为该级别。问题在于公式:brightness + multiplier * brightness,当亮度为 0 或非常小时,这不起作用。因此,您可以创建像这样的颜色 return UIColor(hue: hue, saturation: saturation, brightness: max(min(percentage / 100.0, 1.0), 0.0), alpha: alpha)【参考方案7】:

对于 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
    

【讨论】:

【参考方案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)

【讨论】:

【参考方案9】:

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

用于较深的颜色

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


【讨论】:

【参考方案10】:

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) 

【讨论】:

【参考方案11】:

由于我在当前项目中使用 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))
    

【讨论】:

【参考方案12】:

对于macOS 应用程序,有一个用于颜色混合的内置功能。

要使颜色变浅,只需调用

NSColor.systemRed.blended(withFraction: 0.35, of: .white)

【讨论】:

【参考方案13】:

我正在使用 SwiftUI,正在寻找快速解决方案。

此方法更改 Alpha 通道(0 是透明的,1 是不透明的)并将其置于白色视图的前面,因此您实际上是在将白色与颜色混合。 alpha 值越高,混入的白色越多 = 越亮。

Color 转换为UIColor、修改和转换回来就可以了:

Color(UIColor(Color.blue).withAlphaComponent(0.5))
    .background(Color.white) // IMPORTANT: otherwise your view will be see-through

将颜色变暗 Color.whiteColor.black

【讨论】:

以上是关于为给定的 UIColor 获取更亮和更暗的颜色变化的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript获取某个颜色更亮或更暗的颜色

将检测到的文本设置为比图像更暗 - ccv

如何确定给定颜色的较深或较浅颜色变体?

如何使任何悬停的颜色比原始颜色更暗/更亮

利用伪元素单个颜色实现 hover 和 active 时的明暗变化效果

MATLAB 中的 Gamma 校正实现