编者在实验室小组的指导下,仿写了许多App,其中UI的颜色模仿也是令人头痛的点。设计颜色一般使用UIColor类方法直接获取颜色:
有时会使用
+ (UIColor *)colorWithRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha;
+ (UIColor *)colorWithHue:(CGFloat)hue saturation:(CGFloat)saturation brightness:(CGFloat)brightness alpha:(CGFloat)alpha;
这两个方法,通过取色器获取指定颜色的RGB
参数或HSB
参数。
也会留意到以下这两个方法,本文就此来展开学习:
+(UIColor *)colorWithCGColor:(CGColorRef)cgColor;
#if __has_include(<CoreImage/CoreImage.h>)
+(UIColor *)colorWithCIColor:(CIColor *)ciColor API_AVAILABLE(ios(5.0));
#endif
了解CGColor
、CIColor
前,这里先拓展一个关于颜色的常识,关于颜色空间分类:
UIColor是UIKit中用于表示颜色的类,一个UIColor对象包含了颜色和透明度的值,可以用来表示不同颜色空间(RGB、HSB)的颜色。
UIColor提供了各种便捷的方法创建和管理颜色,正如上面提到的,可以使用与定义的颜色常量,也可以使用RGB或HSB的值来自定义颜色。UIColor还提供了方法来操纵混合、调整透明度等。
CGColor是Core Graphics框架(Apple的绘图框架)中用于表示颜色的数据类型,本质是一个结构体,是一种低级的颜色表示方式,更接近图形底层,提供了底层的图形渲染和绘制功能。
CGColor实际上是指向CGColorRef的指针,主要由CGColorSpace(颜色空间) 和ColorComponents(颜色组成信息)。同样的颜色组成,如果颜色空间不同,解析出来的结果可能会有所不同。
来看一下如何获取CGColor的数据,当然,获取到了CGColorRef后就可以拿到对应的ColorSpace以及Components:
只需将相应的CGColorRef对象传入CGColorGetColorSpace()
函数中
CGColorRef cgColor = [UIColor redColor].CGColor;
CGColorSpaceRef colorSpace = CGColorGetColorSpace(cgColor);
NSLog(@"color space:%@", colorSpace);
可以看到是RGB类型。
先来看看需要用到的两个函数的原型:
可以看到前者返回的是CGColorRef的中包含的颜色组成部分的个数(unsigned long
类型)。
后者返回实际的颜色组成部分的数组(CGFloat *
浮点类型数组),该数组的个数就是指定色彩空间包含的颜色分量数以及对应的alpha值(透明度)。
//获得颜色组成部分的个数
NSUInteger numOfComponents = CGColorGetNumberOfComponents(cgColor);
//获取实际颜色的组成部分的数组
const CGFloat* colorComponents = CGColorGetComponents(cgColor);
for (int i = 0; i < numOfComponents; i++) {
NSLog(@"color components %d : %f", i, colorComponents[i]);
}
既然是颜色空间是RGB类型,那数组的每个值依次对应的是R、G、B、Alpha的值。
CIColor是Core Image框架中用于表示颜色的类,与UIColor有些许相似,但更偏向专门于处理Core Image滤镜中的颜色操作。
CIColor可表示多个颜色空间,包括RGB、HSB、LAB等,它的属性包括颜色分量值(比如R、G、B或H、S、B的值)、透明度等,还提供了一系列方法来创建和操作颜色,如颜色混合、色彩调整等。
CIColor的使用见后面的示例。
不管是通过CGColor、CIColor还是其他方法创建的UIColor,CGColor属性总是有效的,但CIColor属性就不总是有效。只有UIColor是通过CIColor创建时,CIColor才有效,否则访问该属性将会出现异常。
现通过CGColor初始化UIColor来验证一下:
UIColor* color = [UIColor colorWithCGColor: [UIColor whiteColor].CGColor];
NSLog(@"CGColor from UIColor: %@", color.CGColor);
//NSLog(@"CIColor from UIColor: %@", color.CIColor);
正常运行。
如果访问CIColor:
UIColor* color = [UIColor colorWithCGColor: [UIColor whiteColor].CGColor];
//NSLog(@"CGColor from UIColor: %@", color.CGColor);
NSLog(@"CIColor from UIColor: %@", color.CIColor);
crush,程序崩溃。
当使用CGColor初始化UIColor时,所有CGColorRef包含的信息,都会被原封不动地保留(retain),其中就包括Colorspace。
//这里颜色空间使用CMYK
CGColorSpaceRef cmykSpace = CGColorSpaceCreateDeviceCMYK();
CGFloat cmykComponents[] = {1, 1, 0, 0, 1}; //蓝色
CGColorRef colorCMYK = CGColorCreate(cmykSpace, cmykComponents);
CGColorSpaceRelease(cmykSpace);
NSLog(@"colorCMYK:%@", colorCMYK);
//使用CGColor初始化UIColor
UIColor* color = [UIColor colorWithCGColor: colorCMYK];
NSLog(@"CGColor from UIColor:%@", color.CGColor);
当使用CIColor初始化UIColor后,再去访问UIColor的CGColor属性时,会发现CGColor的颜色空间和设置的CIColor的颜色空间不完全一样,这里CIColor已经做了一个转换。下面我们使用Gray(灰度)、RGB、CMYK三种颜色空间来设置CIColor,并初始化UIColor,再去访问其CIColor、CGColor属性,查看颜色空间和颜色信息。
kCGColorSpaceDeviceGray
和kCGColorSpaceDeviceRGB
//白色的颜色空间就是Gray
// NSLog(@"CGColor white color:%@", [UIColor whiteColor].CGColor);
//红色的颜色空间时RGB
NSLog(@"CGColor red color:%@", [UIColor redColor].CGColor);
putchar('\n');
//设置CIColor
CIColor* ciColor = [CIColor colorWithCGColor: [UIColor redColor].CGColor];
NSLog(@"ciColor:%@", ciColor);
NSLog(@"ciColor colorSpace:%@", ciColor.colorSpace);putchar('\n');
//初始化
UIColor* color = [UIColor colorWithCIColor: ciColor];
NSLog(@"color:%@", color);
NSLog(@"ciColor from UIColor:%@", color.CIColor);
NSLog(@"ciColor's colorSpace:%@", color.CIColor.colorSpace);
NSLog(@"color's CGColor:%@", color.CGColor);
可以看到,使用颜色空间为RGB或Gray的CGColor设置CIColor时,CIColor的颜色空间保持不变,通过UIColor访问CIColor和CGColor属性时,颜色空间也保持不变。
kCGColorSpaceDeviceCMYK
CGColorSpaceRef cmykSpace = CGColorSpaceCreateDeviceCMYK();
NSLog(@"Components number: %lu", CGColorSpaceGetNumberOfComponents(cmykSpace));putchar('\n');
CGFloat cmykComponents[] = {1, 1, 0, 0, 1}; //蓝色
CGColorRef colorCMYK = CGColorCreate(cmykSpace, cmykComponents);
CGColorSpaceRelease(cmykSpace);
NSLog(@"colorCMYK:%@", colorCMYK);putchar('\n');
CIColor* ciColor = [CIColor colorWithCGColor: colorCMYK];
NSLog(@"ciColor: %@", ciColor);
NSLog(@"ciColor colorSpace: %@", ciColor.colorSpace);putchar('\n');
UIColor* color = [UIColor colorWithCIColor: ciColor];
NSLog(@"color: %@", color);
NSLog(@"ciColor from UIColor: %@", color.CIColor);
NSLog(@"ciColor's colorSpace: %@", color.CIColor.colorSpace);
NSLog(@"cgColor from UIColor: %@", color.CGColor);
可以看出,使用颜色空间为CMYK的CGColor设置CIColor时,CIColor颜色空间不变,但颜色值已经转换成RGB的颜色值。通过UIColor访问CGColor和CIColor属性时,同样地,颜色空间不变,颜色值改变。
前面提到一点,不管UIColor使用CIColor,CGColor还是其他方式初始化的,其CGColor属性都是可用的。 CoreGraphics中提供一个方法可以判断两个CGColor是否相等,因此我们可以通过判断两个UIColor是否相等:
if (CGColorEqualToColor([UIColor whiteColor].CGColor, [UIColor colorWithRed: 1.0 green: 1.0 blue: 1.0 alpha: 1.0].CGColor)) {
NSLog(@"两颜色相等");
} else {
NSLog(@"两颜色不相等");
}
if (CGColorEqualToColor([UIColor colorWithRed: 1.0 green: 1.0 blue: 1.0 alpha: 1.0].CGColor, [UIColor colorWithRed: 1.0 green: 1.0 blue: 1.0 alpha: 1.0].CGColor)) {
NSLog(@"两颜色相等");
} else {
NSLog(@"两颜色不相等");
}
结果如图,前者虽然都是白色,但颜色空间不一样。