Get lighter and darker color variations for a given UIColor

前端 未结 11 2156
一生所求
一生所求 2021-01-30 02:32

How to get different lighter and darker variations of a given UIColor in Swift?

相关标签:
11条回答
  • 2021-01-30 02:36

    Swift 4 version that supports RGBA, HSBA, and WB (greyscale)

    Here's a variation of TranQuan's answer that also supports greyscale colors like .white and .black. (Note: I removed saturation adjustment because I didn't think it belonged in a simple function like this.)

    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
        }
    }
    
    0 讨论(0)
  • 2021-01-30 02:38

    Since I use SwiftUI in my current project, I adapted the best answer from Stephen. Tested with Xcode 12.0, SwiftUI 2 and 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))
        }
    }
    
    0 讨论(0)
  • 2021-01-30 02:42

    Kenji-Tran's answer works fine, as long as your starting color is not black (brightness value 0). With the addition of a few lines of extra code, you can also make black "lighter" (i.e. brighten it to a grayscale or color value).

    Note: I wasn't able to add this change using an Edit and I'm not allowed to comment on Kenji-Tran's answer due to my "new boy" rep, therefore I found no other way to share my knowledge on SO then by posting a new answer. I hope that's okay.

    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
      }
    }
    
    0 讨论(0)
  • 2021-01-30 02:44

    To save anyone typing, the simple practical version is just

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

    use like

    something.color = .yellow.darker
    

    or

    backgroundColor = backgroundColor.darker
    

    On a large project .................

    You should definitely extend Apple's pattern:

    .withAlphaComponent(_ alpha: CGFloat)
    

    So, have:

    .withBrightnessComponent(_ alpha: CGFloat)
    

    and distinctly

    .withBrightnessComponentAdjustedBy(percentage: CGFloat)
    

    and/or

    .withBrightnessComponentMultipliedBy(factor: CGFloat)
    
    0 讨论(0)
  • 2021-01-30 02:48

    SwiftUI: Color - 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)) }
    }
    

    Reqires one of the followings (or both) for iOS or (and) 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) }
    }
    
    0 讨论(0)
  • 2021-01-30 02:48

    Using lukszar clampled function, I wrote this function for the UIColor extension, using real proportions of RGB values. I hope it is helpful

    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 讨论(0)
提交回复
热议问题