【iOS】UIColor、CGColor、CIColor的区别和联系

编者在实验室小组的指导下,仿写了许多App,其中UI的颜色模仿也是令人头痛的点。设计颜色一般使用UIColor类方法直接获取颜色:

有时会使用

objectivec 复制代码
+ (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参数。

也会留意到以下这两个方法,本文就此来展开学习:

objectivec 复制代码
+(UIColor *)colorWithCGColor:(CGColorRef)cgColor;

#if __has_include(<CoreImage/CoreImage.h>)
+(UIColor *)colorWithCIColor:(CIColor *)ciColor API_AVAILABLE(ios(5.0));
#endif

目录


了解CGColorCIColor前,这里先拓展一个关于颜色的常识,关于颜色空间分类:

  • RGB:R代表红色,G代表绿色,B代表蓝色。通过调整红、绿、蓝的亮度和混合来创建各种颜色,因为三种颜色都有256个亮度水平级,所以三种色彩叠加就形成1670万种颜色了,也就是真彩色,通过它们足以在现绚丽的世界。
  • HSB:H代表色相、S代表饱和度、B代表亮度。基于人类感知,以人眼为理论。色相表示色彩的基本属性,用一个角度值(0~360度)来表示。饱和度表示颜色的鲜艳程度(0~100%)。亮度表示颜色的明暗程度(0~100%)。
  • LAB:L代表亮度,A和B代表色彩。亮度(0~100%)表示由黑到白的程度。A是从深绿色(底亮度)到灰色(中亮度值)再到亮粉红色(高亮度值)。B表示从亮蓝色到灰色再到黄色。可用于描述非线性的颜色变化,广泛应用于色彩匹配和颜色差异度量。
  • CMYK:代表印刷打印上的颜色,C(Cyan)代表青色,M(Magenta)代表洋红色,Y(Yellow)代表黄色,K(Key)代表黑色。在实际应用中,青色、洋红色和黄色很难叠加形成真正的黑色,最深才不过是褐色,因此引入K------黑色,作用是强化暗调,加深暗部色彩。

介绍

UIColor

UIColor是UIKit中用于表示颜色的类,一个UIColor对象包含了颜色和透明度的值,可以用来表示不同颜色空间(RGB、HSB)的颜色。

UIColor提供了各种便捷的方法创建和管理颜色,正如上面提到的,可以使用与定义的颜色常量,也可以使用RGB或HSB的值来自定义颜色。UIColor还提供了方法来操纵混合、调整透明度等。

CGColor

CGColor是Core Graphics框架(Apple的绘图框架)中用于表示颜色的数据类型,本质是一个结构体,是一种低级的颜色表示方式,更接近图形底层,提供了底层的图形渲染和绘制功能。

CGColor实际上是指向CGColorRef的指针,主要由CGColorSpace(颜色空间)ColorComponents(颜色组成信息)。同样的颜色组成,如果颜色空间不同,解析出来的结果可能会有所不同。

来看一下如何获取CGColor的数据,当然,获取到了CGColorRef后就可以拿到对应的ColorSpace以及Components:

  1. 获取ColorSpace

只需将相应的CGColorRef对象传入CGColorGetColorSpace()函数中

objectivec 复制代码
CGColorRef cgColor = [UIColor redColor].CGColor;
CGColorSpaceRef colorSpace = CGColorGetColorSpace(cgColor);
NSLog(@"color space:%@", colorSpace);

可以看到是RGB类型。

  1. 获取ColorComponents

先来看看需要用到的两个函数的原型:

可以看到前者返回的是CGColorRef的中包含的颜色组成部分的个数(unsigned long类型)。

后者返回实际的颜色组成部分的数组(CGFloat *浮点类型数组),该数组的个数就是指定色彩空间包含的颜色分量数以及对应的alpha值(透明度)。

objectivec 复制代码
//获得颜色组成部分的个数
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

CIColor是Core Image框架中用于表示颜色的类,与UIColor有些许相似,但更偏向专门于处理Core Image滤镜中的颜色操作。

CIColor可表示多个颜色空间,包括RGB、HSB、LAB等,它的属性包括颜色分量值(比如R、G、B或H、S、B的值)、透明度等,还提供了一系列方法来创建和操作颜色,如颜色混合、色彩调整等。

CIColor的使用见后面的示例。

UIColor、CGColor、CIColor的区别与联系

UIColor的两个属性CGColor、CIColor

不管是通过CGColorCIColor 还是其他方法创建的UIColor,CGColor 属性总是有效的,但CIColor 属性就不总是有效。只有UIColor是通过CIColor 创建时,CIColor才有效,否则访问该属性将会出现异常。

现通过CGColor初始化UIColor来验证一下:

objectivec 复制代码
UIColor* color = [UIColor colorWithCGColor: [UIColor whiteColor].CGColor];
NSLog(@"CGColor from UIColor: %@", color.CGColor);
//NSLog(@"CIColor from UIColor: %@", color.CIColor);

正常运行。

如果访问CIColor:

objectivec 复制代码
UIColor* color = [UIColor colorWithCGColor: [UIColor whiteColor].CGColor];
//NSLog(@"CGColor from UIColor: %@", color.CGColor);
NSLog(@"CIColor from UIColor: %@", color.CIColor);

crush,程序崩溃。

使用CGColor初始化UIColor

当使用CGColor初始化UIColor时,所有CGColorRef包含的信息,都会被原封不动地保留(retain),其中就包括Colorspace。

objectivec 复制代码
//这里颜色空间使用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

当使用CIColor初始化UIColor后,再去访问UIColor的CGColor属性时,会发现CGColor的颜色空间和设置的CIColor的颜色空间不完全一样,这里CIColor已经做了一个转换。下面我们使用Gray(灰度)、RGB、CMYK三种颜色空间来设置CIColor,并初始化UIColor,再去访问其CIColor、CGColor属性,查看颜色空间和颜色信息。

  1. kCGColorSpaceDeviceGraykCGColorSpaceDeviceRGB
objectivec 复制代码
    //白色的颜色空间就是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属性时,颜色空间也保持不变。

  1. kCGColorSpaceDeviceCMYK
objectivec 复制代码
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拓展:判断两个颜色是否相等

前面提到一点,不管UIColor使用CIColor,CGColor还是其他方式初始化的,其CGColor属性都是可用的。 CoreGraphics中提供一个方法可以判断两个CGColor是否相等,因此我们可以通过判断两个UIColor是否相等:

objectivec 复制代码
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(@"两颜色不相等");
}

结果如图,前者虽然都是白色,但颜色空间不一样。

相关推荐
叽哥6 小时前
Flutter Riverpod上手指南
android·flutter·ios
用户091 天前
SwiftUI Charts 函数绘图完全指南
ios·swiftui·swift
YungFan1 天前
iOS26适配指南之UIColor
ios·swift
权咚2 天前
阿权的开发经验小集
git·ios·xcode
用户092 天前
TipKit与CloudKit同步完全指南
ios·swift
小溪彼岸2 天前
macOS自带截图命令ScreenCapture
macos
法的空间2 天前
Flutter JsonToDart 支持 JsonSchema
android·flutter·ios
2501_915918412 天前
iOS 上架全流程指南 iOS 应用发布步骤、App Store 上架流程、uni-app 打包上传 ipa 与审核实战经验分享
android·ios·小程序·uni-app·cocoa·iphone·webview
TESmart碲视2 天前
Mac 真正多显示器支持:TESmart USB-C KVM(搭载 DisplayLink 技术)如何实现
macos·计算机外设·电脑
00后程序员张2 天前
iOS App 混淆与加固对比 源码混淆与ipa文件混淆的区别、iOS代码保护与应用安全场景最佳实践
android·安全·ios·小程序·uni-app·iphone·webview