Skip to content

Instantly share code, notes, and snippets.

@luowei
Created November 21, 2016 03:54
Show Gist options
  • Save luowei/c680dcfb9d19672232125a7c02a4ef30 to your computer and use it in GitHub Desktop.
Save luowei/c680dcfb9d19672232125a7c02a4ef30 to your computer and use it in GitHub Desktop.
UIColor OC扩展
@interface UIColor (CrossFade)
/**
* Fades between firstColor and secondColor at the specified ratio:
*
* @ ratio 0.0 - fully firstColor
* @ ratio 0.5 - halfway between firstColor and secondColor
* @ ratio 1.0 - fully secondColor
*
*/
+ (UIColor *)colorForFadeBetweenFirstColor:(UIColor *)firstColor
secondColor:(UIColor *)secondColor
atRatio:(CGFloat)ratio;
/**
* Same as above, but allows turning off the color space comparison
* for a performance boost.
*/
+ (UIColor *)colorForFadeBetweenFirstColor:(UIColor *)firstColor secondColor:(UIColor *)secondColor atRatio:(CGFloat)ratio compareColorSpaces:(BOOL)compare;
//根据比例与alpha值得到一个过渡色
+ (UIColor *)colorBetweenFirstColor:(UIColor *)firstColor secondColor:(UIColor *)secondColor atRatio:(CGFloat)ratio withAlpha:(CGFloat)alpha;
/**
* An array of [steps] colors starting with firstColor, continuing with linear interpolations
* between firstColor and lastColor and ending with lastColor.
*/
+ (NSArray *)colorsForFadeBetweenFirstColor:(UIColor *)firstColor
lastColor:(UIColor *)lastColor
inSteps:(NSUInteger)steps;
/**
* An array of [steps] colors starting with firstColor, continuing with interpolations, as specified
* by the equation block, between firstColor and lastColor and ending with lastColor. The equation block
* must take a float as an input, and return a float as an output. Output will be santizied to be between
* a ratio of 0.0 and 1.0. Passing nil for the equation results in a linear relationship.
*/
+ (NSArray *)colorsForFadeBetweenFirstColor:(UIColor *)firstColor
lastColor:(UIColor *)lastColor
withRatioEquation:(float (^)(float input))equation
inSteps:(NSUInteger)steps;
/**
* Convert UIColor to RGBA colorspace. Used for cross-colorspace interpolation.
*/
+ (UIColor *)colorConvertedToRGBA:(UIColor *)colorToConvert;
/**
* Creates a CAKeyframeAnimation for the given key path, duration, and first/last colors that can be
* applied to an appropriate CALayer property (i.e. backgroundColor). See the demo for example usage.
*/
+ (CAKeyframeAnimation *)keyframeAnimationForKeyPath:(NSString *)keyPath
duration:(NSTimeInterval)duration
betweenFirstColor:(UIColor *)firstColor
lastColor:(UIColor *)lastColor;
/**
* Same as above, but allows setting a ratio equation (for non-linear transitions between colors) and
* the number of steps to calculate. Decreasing steps may improve performance as it decreases the number
* of cross-fade calculations necessary.
*/
+ (CAKeyframeAnimation *)keyframeAnimationForKeyPath:(NSString *)keyPath
duration:(NSTimeInterval)duration
betweenFirstColor:(UIColor *)firstColor
lastColor:(UIColor *)lastColor
withRatioEquation:(float (^)(float))equation
inSteps:(NSUInteger)steps;
@end
//======= HexValue =======
@interface UIColor (HexValue)
+ (UIColor *)colorWithRGBAString:(NSString *)RGBAString;
+ (UIColor *)colorWithHexString:(NSString *)hex;
//从UIColor得到RGBA字符串
+(NSString *)rgbaStringFromUIColor:(UIColor *)color;
+(NSString *)hexValuesFromUIColor:(UIColor *)color;
+ (UIColor *)colorWithHex:(uint)hex alpha:(CGFloat)alpha;
@end
//------- Implamentation --------
@implementation UIColor (CrossFade)
+ (UIColor *)colorForFadeBetweenFirstColor:(UIColor *)firstColor
secondColor:(UIColor *)secondColor
atRatio:(CGFloat)ratio {
return [self colorForFadeBetweenFirstColor:firstColor secondColor:secondColor atRatio:ratio compareColorSpaces:YES];
}
+ (UIColor *)colorForFadeBetweenFirstColor:(UIColor *)firstColor secondColor:(UIColor *)secondColor atRatio:(CGFloat)ratio compareColorSpaces:(BOOL)compare {
// Eliminate values outside of 0 <--> 1
ratio = MIN(MAX(0, ratio), 1);
// Convert to common RGBA colorspace if needed
if (compare) {
if (CGColorGetColorSpace(firstColor.CGColor) != CGColorGetColorSpace(secondColor.CGColor)) {
firstColor = [UIColor colorConvertedToRGBA:firstColor];
secondColor = [UIColor colorConvertedToRGBA:secondColor];
}
}
// Grab color components
const CGFloat *firstColorComponents = CGColorGetComponents(firstColor.CGColor);
const CGFloat *secondColorComponents = CGColorGetComponents(secondColor.CGColor);
// Interpolate between colors
CGFloat interpolatedComponents[CGColorGetNumberOfComponents(firstColor.CGColor)];
for (NSUInteger i = 0; i < CGColorGetNumberOfComponents(firstColor.CGColor); i++) {
interpolatedComponents[i] = firstColorComponents[i] * (1 - ratio) + secondColorComponents[i] * ratio;
}
// Create interpolated color
CGColorRef interpolatedCGColor = CGColorCreate(CGColorGetColorSpace(firstColor.CGColor), interpolatedComponents);
UIColor *interpolatedColor = [UIColor colorWithCGColor:interpolatedCGColor];
CGColorRelease(interpolatedCGColor);
return interpolatedColor;
}
//根据比例与alpha值得到一个过渡色
+ (UIColor *)colorBetweenFirstColor:(UIColor *)firstColor secondColor:(UIColor *)secondColor atRatio:(CGFloat)ratio withAlpha:(CGFloat)alpha{
// Eliminate values outside of 0 <--> 1
ratio = MIN(MAX(0, ratio), 1);
// Convert to common RGBA colorspace if needed
if (CGColorGetColorSpace(firstColor.CGColor) != CGColorGetColorSpace(secondColor.CGColor)) {
firstColor = [UIColor colorConvertedToRGBA:firstColor];
secondColor = [UIColor colorConvertedToRGBA:secondColor];
}
// Grab color components
const CGFloat *firstColorComponents = CGColorGetComponents(firstColor.CGColor);
const CGFloat *secondColorComponents = CGColorGetComponents(secondColor.CGColor);
// Interpolate between colors
CGFloat interpolatedComponents[CGColorGetNumberOfComponents(firstColor.CGColor)];
for (NSUInteger i = 0; i < CGColorGetNumberOfComponents(firstColor.CGColor); i++) {
if(i == 3){
//把alpha通道值设置为alpha
interpolatedComponents[i] = alpha;
}else{
interpolatedComponents[i] = firstColorComponents[i] * (1 - ratio) + secondColorComponents[i] * ratio;
}
}
// Create interpolated color
CGColorRef interpolatedCGColor = CGColorCreate(CGColorGetColorSpace(firstColor.CGColor), interpolatedComponents);
UIColor *interpolatedColor = [UIColor colorWithCGColor:interpolatedCGColor];
CGColorRelease(interpolatedCGColor);
return interpolatedColor;
}
+ (NSArray *)colorsForFadeBetweenFirstColor:(UIColor *)firstColor
lastColor:(UIColor *)lastColor
inSteps:(NSUInteger)steps {
return [self colorsForFadeBetweenFirstColor:firstColor lastColor:lastColor withRatioEquation:nil inSteps:steps];
}
+ (NSArray *)colorsForFadeBetweenFirstColor:(UIColor *)firstColor lastColor:(UIColor *)lastColor withRatioEquation:(float (^)(float input))equation inSteps:(NSUInteger)steps {
// Handle degenerate cases
if (steps == 0)
return nil;
if (steps == 1)
return [NSArray arrayWithObject:firstColor];
if (steps == 2)
return [NSArray arrayWithObjects:firstColor, lastColor, nil];
// Assume linear if no equation is passed
if (equation == nil) {
equation = ^(float input) {
return input;
};
}
// Calculate step size
CGFloat stepSize = 1.0f / (steps - 1);
// Array to store colors in steps
NSMutableArray *colors = [[NSMutableArray alloc] initWithCapacity:steps];
[colors addObject:firstColor];
// Compute intermediate colors
CGFloat ratio = stepSize;
for (int i = 2; i < steps; i++) {
[colors addObject:[self colorForFadeBetweenFirstColor:firstColor secondColor:lastColor atRatio:equation(ratio)]];
ratio += stepSize;
}
[colors addObject:lastColor];
return colors;
}
+ (CAKeyframeAnimation *)keyframeAnimationForKeyPath:(NSString *)keyPath
duration:(NSTimeInterval)duration
betweenFirstColor:(UIColor *)firstColor
lastColor:(UIColor *)lastColor {
return [UIColor keyframeAnimationForKeyPath:keyPath
duration:duration
betweenFirstColor:firstColor
lastColor:lastColor
withRatioEquation:^float(float input) {
return input;
} inSteps:floorf(duration * 30.0f)];
}
+ (CAKeyframeAnimation *)keyframeAnimationForKeyPath:(NSString *)keyPath
duration:(NSTimeInterval)duration
betweenFirstColor:(UIColor *)firstColor
lastColor:(UIColor *)lastColor
withRatioEquation:(float (^)(float input))equation
inSteps:(NSUInteger)steps {
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:keyPath];
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
animation.duration = duration;
NSArray *colorRefs = [[self colorsForFadeBetweenFirstColor:firstColor lastColor:lastColor withRatioEquation:equation inSteps:steps] valueForKeyPath:@"CCF_CGColor"];
animation.values = colorRefs;
return animation;
}
#pragma mark - Helpers
+ (UIColor *)colorConvertedToRGBA:(UIColor *)colorToConvert; {
CGFloat red;
CGFloat green;
CGFloat blue;
CGFloat alpha;
// Convert color to RGBA with a CGContext. UIColor's getRed:green:blue:alpha: doesn't work across color spaces. Adapted from http://stackoverflow.com/a/4700259
alpha = CGColorGetAlpha(colorToConvert.CGColor);
CGColorRef opaqueColor = CGColorCreateCopyWithAlpha(colorToConvert.CGColor, 1.0f);
CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
unsigned char resultingPixel[CGColorSpaceGetNumberOfComponents(rgbColorSpace)];
CGContextRef context = CGBitmapContextCreate(&resultingPixel, 1, 1, 8, 4, rgbColorSpace, (CGBitmapInfo) kCGImageAlphaNoneSkipLast);
CGContextSetFillColorWithColor(context, opaqueColor);
CGColorRelease(opaqueColor);
CGContextFillRect(context, CGRectMake(0.f, 0.f, 1.f, 1.f));
CGContextRelease(context);
CGColorSpaceRelease(rgbColorSpace);
red = resultingPixel[0] / 255.0f;
green = resultingPixel[1] / 255.0f;
blue = resultingPixel[2] / 255.0f;
return [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
}
- (id)valueForUndefinedKey:(NSString *)key {
if ([key isEqualToString:@"CCF_CGColor"]) {
return (id) self.CGColor;
}
return [super valueForUndefinedKey:key];
}
@end
//========= HexValue ==========
@implementation UIColor (HexValue)
+ (UIColor *)colorWithRGBAString:(NSString *)RGBAString {
UIColor *color = nil;
NSArray *rgbaComponents = [RGBAString componentsSeparatedByString:@","];
float RED = 0.0f;
float GREEN = 0.0f;
float BLUE = 0.0f;
float ALPHA = 0.0f;
//string like : 127,127,127
if ([rgbaComponents count] == 3) {
RED = [(NSString*) rgbaComponents[0] floatValue]/255;
GREEN = [(NSString*) rgbaComponents[1] floatValue]/255;
BLUE = [(NSString*) rgbaComponents[2] floatValue]/255;
color = [UIColor colorWithRed:RED green:GREEN blue:BLUE alpha:1.0f];
//string like : 127,127,127,255
}else if ([rgbaComponents count] == 4) {
RED = [(NSString*) rgbaComponents[0] floatValue]/255;
GREEN = [(NSString*) rgbaComponents[1] floatValue]/255;
BLUE = [(NSString*) rgbaComponents[2] floatValue]/255;
ALPHA = [(NSString*) rgbaComponents[3] floatValue]/255;
color = [UIColor colorWithRed:RED green:GREEN blue:BLUE alpha:ALPHA];
}
return color;
}
+(UIColor *)colorWithHexString:(NSString *)hexString {
if ([hexString length] != 6) {
return nil;
}
// Brutal and not-very elegant test for non hex-numeric characters
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"[^a-fA-F|0-9]" options:0 error:NULL];
NSUInteger match = [regex numberOfMatchesInString:hexString options:NSMatchingReportCompletion range:NSMakeRange(0, [hexString length])];
if (match != 0) {
return nil;
}
NSRange rRange = NSMakeRange(0, 2);
NSString *rComponent = [hexString substringWithRange:rRange];
NSUInteger rVal = 0;
NSScanner *rScanner = [NSScanner scannerWithString:rComponent];
[rScanner scanHexInt:((unsigned *)(&rVal))];
float rRetVal = (float)rVal / 254;
NSRange gRange = NSMakeRange(2, 2);
NSString *gComponent = [hexString substringWithRange:gRange];
NSUInteger gVal = 0;
NSScanner *gScanner = [NSScanner scannerWithString:gComponent];
[gScanner scanHexInt:((unsigned *)(&rVal))];
float gRetVal = (float)gVal / 254;
NSRange bRange = NSMakeRange(4, 2);
NSString *bComponent = [hexString substringWithRange:bRange];
NSUInteger bVal = 0;
NSScanner *bScanner = [NSScanner scannerWithString:bComponent];
[bScanner scanHexInt:((unsigned *)(&rVal))];
float bRetVal = (float)bVal / 254;
return [UIColor colorWithRed:rRetVal green:gRetVal blue:bRetVal alpha:1.0f];
}
+(NSString *)hexValuesFromUIColor:(UIColor *)color {
if (!color) {
return nil;
}
if (color == [UIColor whiteColor]) {
// Special case, as white doesn't fall into the RGB color space
return @"ffffff";
}
CGFloat red;
CGFloat blue;
CGFloat green;
CGFloat alpha;
[color getRed:&red green:&green blue:&blue alpha:&alpha];
int redDec = (int)(red * 255);
int greenDec = (int)(green * 255);
int blueDec = (int)(blue * 255);
NSString *returnString = [NSString stringWithFormat:@"%02x%02x%02x", (unsigned int)redDec, (unsigned int)greenDec, (unsigned int)blueDec];
return returnString;
}
//从UIColor得到RGBA字符串
+(NSString *)rgbaStringFromUIColor:(UIColor *)color {
if (!color) {
return nil;
}
if (color == [UIColor whiteColor]) {
// Special case, as white doesn't fall into the RGB color space
return @"255,255,255,255";
}
CGFloat red;
CGFloat blue;
CGFloat green;
CGFloat alpha;
[color getRed:&red green:&green blue:&blue alpha:&alpha];
int redDec = (int)(red * 255);
int greenDec = (int)(green * 255);
int blueDec = (int)(blue * 255);
int alphaDec = (int)(alpha * 255);
NSString *returnString = [NSString stringWithFormat:@"%d,%d,%d,%d", (unsigned int)redDec, (unsigned int)greenDec, (unsigned int)blueDec,(unsigned int)alphaDec];
return returnString;
}
+ (UIColor *)colorWithHex:(uint)hex alpha:(CGFloat)alpha {
int red, green, blue;
blue = hex & 0x0000FF;
green = ((hex & 0x00FF00) >> 8);
red = ((hex & 0xFF0000) >> 16);
return [UIColor colorWithRed:red / 255.0f green:green / 255.0f blue:blue / 255.0f alpha:alpha];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment