可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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.
回答1:
- (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
回答2:
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:
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;
}
回答3:
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 :
回答4:
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()
}
回答5:
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:
// UIColor+Mix.swift
import UIKit
extension UIColor {
func mixLighter (amount: CGFloat = 0.25) -> UIColor {
return mixWithColor(UIColor.whiteColor(), amount:amount)
}
func mixDarker (amount: CGFloat = 0.25) -> UIColor {
return mixWithColor(UIColor.blackColor(), amount:amount)
}
func mixWithColor(color: UIColor, amount: CGFloat = 0.25) -> UIColor {
var r1 : CGFloat = 0
var g1 : CGFloat = 0
var b1 : CGFloat = 0
var alpha1 : CGFloat = 0
var r2 : CGFloat = 0
var g2 : CGFloat = 0
var b2 : CGFloat = 0
var alpha2 : CGFloat = 0
self.getRed (&r1, green: &g1, blue: &b1, alpha: &alpha1)
color.getRed(&r2, green: &g2, blue: &b2, alpha: &alpha2)
return UIColor( red:r1*(1.0-amount)+r2*amount,
green:g1*(1.0-amount)+g2*amount,
blue:b1*(1.0-amount)+b2*amount,
alpha: alpha1 )
}
}
Here are examples with some colors
回答6:
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.
回答7:
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.
回答8:
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
.
回答9:
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()
}
}
回答10:
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()
回答11:
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?
回答12:
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!
回答13:
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()
}
}
回答14:
I render coloured cells based on a status value:
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
.
回答15:
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;
}
回答16:
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()
}
}
回答17:
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.