Get Slightly Lighter and Darker Color from UIColor

Objective CIosCore GraphicsGradientUicolor

Objective C Problem Overview


I was looking to be able to turn any UIColor into a gradient. The way I am intending to do this is by using Core Graphics to draw a gradient. What I am trying to do is to get a color, lets say:

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

and get a UIColor which is a few shades darker and a few shades lighter. Does anyone know how to do this? Thank you.

Objective C Solutions


Solution 1 - Objective C

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

Use it like this:

UIColor *baseColor = // however you obtain your color
UIColor *lighterColor = [self lighterColorForColor:baseColor];
UIColor *darkerColor = [self darkerColorForColor:baseColor];

EDIT: as @Anchu Chimala pointed out, for maximum flexibility, these methods should be implemented as an UIColor category. Also, from @Riley's idea, it may be a better idea to make the color proprtionally darker or lighter instead of adding or subtracting constant values. As @jrturton pointed out, it's not necessary to manipulate the RGB components; it's better to modify the brightness property itself. All in all:

@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

Solution 2 - Objective C

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

Usage:

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 was right in his comment to @user529758 (The accepted answer) - The HSB (Or HSV) and RGB solutions give completely different results. RGB just adds (Or makes the color closer to) white, and the HSB solution brings the color closer to the edge in the Brigtness scale - which basically start with black and ends with the pure color...

Basically Brightness (Value) makes the color less or more closer to black, where Saturation makes it less or more closer to white...

As seen here:

HSV color graph

So the solution to make a color actually brighter (i.e. closer to white...) will be to make it's Saturation value smaller, resulting this solution:

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

Solution 3 - Objective C

Swift universal extension for iOS and OS X, using 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

    }
    
}

Usage :

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)

OR (with the default values):

color.lighter()
color.darker()

Sample :

enter image description here

Solution 4 - Objective C

I just wanted to give the same result, in RGB, than

  • placing the color with alpha x% over a white background to lighten
  • placing the color with alpha x% over a black background to darken

Which gives the same result, AFAIK, than picking the color in a gradient 'color to white' or 'color to black', at x% of the gradient size.

For that purpose, the math is simple:

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

Here are examples with some colors

Examples Darker and Lighter

Solution 5 - Objective C

user529758's solution in Swift:

Darker color:

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

Lighter color:

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

Solution 6 - Objective C

If you convert the RGB color to the HSL color model then you can vary the L = lightness component from L = 0.0 (black) over L = 0.5 (natural color) to L = 1.0 (white) . UIColor cannot handle HSL directly, but there are formula for converting RGB <-> HSL.

Solution 7 - Objective C

All other answers in this thread use either the RGB color system or simply change the hue or brightness value of the HSB system. As explained in detail in this great blog post the correct way of making a color lighter or darker is to change its luminance value. None of the other answers does that. If you want to do it right, then use my solution or write your own after reading the blog post.


Unfortunately it's quite a hassle to change any of the attributes of a UIColor by default. Also Apple doesn't even support any LAB-based color space like HCL in the UIColor class (the L in LAB is the luminance value we are looking for).

Using HandyUIKit (install it via Carthage) adds support for HCL and makes your life a lot easier:

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)

There is also an option to apply a relative change (recommended):

// create a new UIColor object with slightly darker color
color.change(.luminance, by: -0.2)

Note that HandyUIKit also adds some other handy UI features into your project – checkout its README on GitHub for more details.

I hope it helps!

Disclaimer: I'm the author of HandyUIKit.

Solution 8 - Objective C

None of the solutions posted quite worked for all colours and shades, but then I stumbled across this library which provides a set of very well implemented extensions to UIColor.

Specifically it has a lighten function as part of its HSL implementation: (UIColor *)lighten:(CGFloat)amount - which works perfectly.

Solution 9 - Objective C

Sebyddd solution as an extension:

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

Usage:

let darkerYellow = UIColor.yellow.darker()
let lighterYellow = UIColor.yellow.lighter()

Solution 10 - Objective C

If you want user529758's solution to work with gray shades (like [UIColor lightGrayColor] or [UIColor darkGrayColor] you have to improve it like that:

- (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 fails (and returns false) when called on a gray shade therefore you'll need to use getWhite:alpha.

Solution 11 - Objective C

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

Solution 12 - Objective C

UIColor extension and fixing 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()
  }
}

Solution 13 - Objective C

I'm not sure if you're looking for some sort of Objective-C answer, but based on how colors specified by RGBA work, I think you can simply scale the RGB values according to an arbitrary factor to get a "lighter" or "darker" shade. For example, you might have a blue:

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

Want a darker blue? Multiply the RGB values by 0.9:

[UIColor colorWithRed:0.0 green:0.0 blue:0.9 alpha:1.0];

Voila. Or maybe you have an orange:

[UIColor colorWithRed:1.0 green:0.4 blue:0.0 alpha:1.0];

Choose another scale factor, say, 0.8:

[UIColor colorWithRed:0.8 green:0.32 blue:0.0 alpha:1.0];

Is that the sort of effect you're looking for?

Solution 14 - Objective C

Tested in Xcode 10 with Swift 4.x for iOS 12

Start with your color as a UIColor and pick a darkening factor (as a CGFloat)

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

The type CGColor has an optional value components which break down the color into RGBA (as a CGFloat array with values between 0 and 1). You can then reconstruct a UIColor using RGBA values taken from the CGColor and manipulate them.

let darkenedBase = UIColor(displayP3Red: startColor.cgColor.components![0] / darkenFactor, green: startColor.cgColor.components![1] / darkenFactor, blue: startColor.cgColor.components![2] / darkenFactor, alpha: 1)

In this example, each of the RGB valuse were divided by 2, making the color half as dark as it was before. The alpha value remained the same, but you could alternatively apply the darken factor on the alpha value rather than the RGB.

Solution 15 - Objective C

Ideally, the functions should be encapsulated inside a UIColor extension called, UIColor+Brightness.swift, and have a configurable brightness - see example below:

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

Solution 16 - Objective C

I render coloured cells based on a status value:

status-images

For this I wrote a swift extension based on some old objc code after I got an error using CryingHippo's suggestion:

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

The same works for NSColor as well. Simply replace UIColor with NSColor.

Solution 17 - Objective C

Here is a UIColor category that also allows control over the amount of color change.

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

Solution 18 - Objective C

A Swift extension based on @Sebyddd answer:

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

Solution 19 - Objective C

for darker color, this is the simplest: theColor = [theColor shadowWithLevel:s]; //s:0.0 to 1.0

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCoreCodeView Question on Stackoverflow
Solution 1 - Objective Cuser529758View Answer on Stackoverflow
Solution 2 - Objective CAviel GrossView Answer on Stackoverflow
Solution 3 - Objective CCryingHippoView Answer on Stackoverflow
Solution 4 - Objective CFredericPView Answer on Stackoverflow
Solution 5 - Objective CSebydddView Answer on Stackoverflow
Solution 6 - Objective CMartin RView Answer on Stackoverflow
Solution 7 - Objective CJeehutView Answer on Stackoverflow
Solution 8 - Objective CRyanView Answer on Stackoverflow
Solution 9 - Objective CHemangView Answer on Stackoverflow
Solution 10 - Objective CMatthieu RieglerView Answer on Stackoverflow
Solution 11 - Objective CAhmadrezaView Answer on Stackoverflow
Solution 12 - Objective CJustin Levi WinterView Answer on Stackoverflow
Solution 13 - Objective CravronView Answer on Stackoverflow
Solution 14 - Objective CMicrobobView Answer on Stackoverflow
Solution 15 - Objective CZorayrView Answer on Stackoverflow
Solution 16 - Objective CBesiView Answer on Stackoverflow
Solution 17 - Objective CBlagoView Answer on Stackoverflow
Solution 18 - Objective CBalázs VinczeView Answer on Stackoverflow
Solution 19 - Objective CJiulong ZhaoView Answer on Stackoverflow