如何比较 UIColors?

我想检查一下 UIImageView 的背景颜色设置,我试过:

if(myimage.backgroundColor == [UIColor greenColor]){
...}
else{
...}

但这不管用,即使我知道颜色是绿色,它也总是落在别的部分。

另外,是否有方法在调试控制台中输出当前颜色。

p [myimage backgroundColor]

还有

po [myimage backgroundColor]

没用。

54804 次浏览

你试过 [myColor isEqual:someOtherColor]吗?

if([myimage.backgroundColor isEqual:[UIColor greenColor]])

正如 zoul 在评论中指出的,当比较不同型号/空间的颜色时(例如 #FFF[UIColor whiteColor]) ,isEqual:将返回 NO。我编写了这个 UIColor 扩展,它在比较两种颜色之前将它们转换为相同的颜色空间:

- (BOOL)isEqualToColor:(UIColor *)otherColor {
CGColorSpaceRef colorSpaceRGB = CGColorSpaceCreateDeviceRGB();


UIColor *(^convertColorToRGBSpace)(UIColor*) = ^(UIColor *color) {
if (CGColorSpaceGetModel(CGColorGetColorSpace(color.CGColor)) == kCGColorSpaceModelMonochrome) {
const CGFloat *oldComponents = CGColorGetComponents(color.CGColor);
CGFloat components[4] = {oldComponents[0], oldComponents[0], oldComponents[0], oldComponents[1]};
CGColorRef colorRef = CGColorCreate( colorSpaceRGB, components );


UIColor *color = [UIColor colorWithCGColor:colorRef];
CGColorRelease(colorRef);
return color;
} else
return color;
};


UIColor *selfColor = convertColorToRGBSpace(self);
otherColor = convertColorToRGBSpace(otherColor);
CGColorSpaceRelease(colorSpaceRGB);


return [selfColor isEqual:otherColor];
}
#import "UIColor-Expanded.h"
//https://github.com/thetaplab/uicolor-utilities


//RGB distance
CGFloat distance = sqrtf(powf((clr0.red - clr1.red), 2) + powf((clr0.green - clr1.green), 2) + powf((clr0.blue - clr1.blue), 2) );
if(distance<=minDistance){
....
}else{
...
}

当你像这样比较 myimage.backgroundColor == [UIColor greenColor]的时候,如果你没有在这个语句之前把 backoundColor 改成绿色,那么它就不起作用了。

我有同样的问题在我的颜色游戏,我解决了,通过使用 RGB 颜色的简单差分方程,你可以快速看看短代码样本从 给你的颜色过程

就像胜利者的回答

GFloat distance = sqrtf(powf((clr0.red - clr1.red), 2) + powf((clr0.green - clr1.green), 2) + powf((clr0.blue - clr1.blue), 2) );
if(distance<=minDistance){
....
}else{
…
}

您可以使用

include "UIColorProcess.h"


..


float distance = [UIColorProcess findDistanceBetweenTwoColor:[UIColor redColor] secondColor:[UIColor blueColor]];

当然,如果它返回0,那就意味着你比较的颜色太相似了。返回范围大概是(0.0 f-1.5 f)。.

那么:

+(BOOL)color:(UIColor *)color1 matchesColor:(UIColor *)color2
{
CGFloat red1, red2, green1, green2, blue1, blue2, alpha1, alpha2;
[color1 getRed:&red1 green:&green1 blue:&blue1 alpha:&alpha1];
[color2 getRed:&red2 green:&green2 blue:&blue2 alpha:&alpha2];


return (red1 == red2 && green1 == green2 && blue1 == blue2 && alpha1 == alpha2);
}

这个类别是我写的。如果 isEqual:确实返回 NO,它将测试不同组件的进一步比较是否仍然匹配。如果可能的话,不同的模型仍然可以进行比较。

@implementation UIColor (Matching)




-(BOOL)matchesColor:(UIColor *)color error:(NSError *__autoreleasing *)error
{
UIColor *lhs = self;
UIColor *rhs = color;


if([lhs isEqual:rhs]){ // color model and values are the same
return YES;
}


CGFloat red1, red2, green1, alpha1, green2, blue1, blue2, alpha2;
BOOL lhsSuccess = [lhs getRed:&red1 green:&green1 blue:&blue1 alpha:&alpha1];
BOOL rhsSuccess = [rhs getRed:&red2 green:&green2 blue:&blue2 alpha:&alpha2];
if((!lhsSuccess && rhsSuccess) || (lhsSuccess && !rhsSuccess)){ // one is RGBA, one color not.
CGFloat r,g,b,a;
if(!lhsSuccess){ // lhs color could be a monochrome
const CGFloat *components = CGColorGetComponents(lhs.CGColor);
if([lhs _colorSpaceModel] == kCGColorSpaceModelMonochrome){
r = g = b = components[0];
a = components[1];


return r == red2 && g == green2 && b == blue2 && a == alpha2;
}
} else {  // rhs color could be a monochrome
const CGFloat *components = CGColorGetComponents(rhs.CGColor);


if([rhs _colorSpaceModel] == kCGColorSpaceModelMonochrome){
r = g = b = components[0];
a = components[1];
return r == red1 && g == green1 && b == blue1 && a == alpha1;
}
}




NSError *aError = [[NSError alloc] initWithDomain:@"UIColorComparision" code:-11111 userInfo:[self _colorComparisionErrorUserInfo]];
*error = aError;
return  NO;
} else if (!lhsSuccess && !rhsSuccess){ // both not RGBA, lets try HSBA
CGFloat hue1,saturation1,brightness1;
CGFloat hue2,saturation2,brightness2;


lhsSuccess = [lhs getHue:&hue1 saturation:&saturation1 brightness:&brightness1 alpha:&alpha1];
rhsSuccess = [lhs getHue:&hue2 saturation:&saturation2 brightness:&brightness2 alpha:&alpha2];
if((!lhsSuccess && rhsSuccess) || (lhsSuccess && !rhsSuccess)){
NSError *aError = [[NSError alloc] initWithDomain:@"UIColorComparision" code:-11111 userInfo:[self _colorComparisionErrorUserInfo]];
*error = aError;
return  NO;
} else if(!lhsSuccess && !rhsSuccess){ // both not HSBA, lets try monochrome
CGFloat white1, white2;


lhsSuccess = [lhs getWhite:&white1 alpha:&alpha1];
rhsSuccess = [rhs getWhite:&white2 alpha:&alpha2];
if((!lhsSuccess && rhsSuccess) || (lhsSuccess && !rhsSuccess)){
NSError *aError = [[NSError alloc] initWithDomain:@"UIColorComparision" code:-11111 userInfo:[self _colorComparisionErrorUserInfo]];
*error = aError;
return  NO;
} else {
return white1 == white2 && alpha1 == alpha2;
}


} else {
return hue1 == hue2 && saturation1 == saturation2 && brightness1 == brightness2 && alpha1 == alpha2;
}


} else {
return (red1 == red2 && green1 == green2 && blue1 == blue2 && alpha1 == alpha2);


}
}


-(NSDictionary *)_colorComparisionErrorUserInfo{


NSDictionary *userInfo = @{
NSLocalizedDescriptionKey: NSLocalizedString(@"Comparision failed.", nil),
NSLocalizedFailureReasonErrorKey: NSLocalizedString(@"The colors models are incompatible. Or the color is a pattern.", nil),


};
return userInfo;
}


- (CGColorSpaceModel)_colorSpaceModel {
return CGColorSpaceGetModel(CGColorGetColorSpace(self.CGColor));
}


@end

UIColor *green1 = [UIColor greenColor];
UIColor *green2 = [UIColor colorWithRed:0 green:1 blue:0 alpha:1];
UIColor *yellow = [UIColor yellowColor];
UIColor *grey1  = [UIColor colorWithWhite:2.0/3.0 alpha:1];
UIColor *grey2  = [UIColor lightGrayColor];


NSError *error1, *error2, *error3, *error4, *error5;


BOOL match1 = [green1 matchesColor:green2 error:&error1];   // YES
BOOL match2 = [green1 matchesColor:yellow error:&error2];   // NO
BOOL match3 = [green1 matchesColor:grey1 error:&error3];    // NO
BOOL match4 = [grey1 matchesColor:grey2 error:&error4];     // YES
BOOL match5 = [grey1 matchesColor:[UIColor colorWithPatternImage:[UIImage imageNamed:@"bg.png"]]
error:&error5];                 // NO, Error

这可能有点太晚了,但是 CoreGraphics 有一个更简单的 API 来实现这一点:

CGColorEqualToColor(myColor.CGColor, [UIColor clearColor].CGColor)

就像文件上说的:

指示两种颜色是否相等。 如果两种颜色具有相同的颜色空间和数值相等的颜色分量,则它们相等。

这解决了很多问题和漏洞/自定义算法。

Samvermette 的解决办法转化为迅速:

extension UIColor {
func isEqualToColor(otherColor : UIColor) -> Bool {
if self == otherColor {
return true
}


let colorSpaceRGB = CGColorSpaceCreateDeviceRGB()
let convertColorToRGBSpace : ((color : UIColor) -> UIColor?) = { (color) -> UIColor? in
if CGColorSpaceGetModel(CGColorGetColorSpace(color.CGColor)) == CGColorSpaceModel.Monochrome {
let oldComponents = CGColorGetComponents(color.CGColor)
let components : [CGFloat] = [ oldComponents[0], oldComponents[0], oldComponents[0], oldComponents[1] ]
let colorRef = CGColorCreate(colorSpaceRGB, components)
let colorOut = UIColor(CGColor: colorRef!)
return colorOut
}
else {
return color;
}
}


let selfColor = convertColorToRGBSpace(color: self)
let otherColor = convertColorToRGBSpace(color: otherColor)


if let selfColor = selfColor, otherColor = otherColor {
return selfColor.isEqual(otherColor)
}
else {
return false
}
}
}

可能会出现一些奇怪的舍入错误。这可能是一个对象设置为一种颜色和你设置它的颜色不完全匹配的原因。

我是这样解决的:

private func compareColors (c1:UIColor, c2:UIColor) -> Bool{
// some kind of weird rounding made the colors unequal so had to compare like this


var red:CGFloat = 0
var green:CGFloat  = 0
var blue:CGFloat = 0
var alpha:CGFloat  = 0
c1.getRed(&red, green: &green, blue: &blue, alpha: &alpha)


var red2:CGFloat = 0
var green2:CGFloat  = 0
var blue2:CGFloat = 0
var alpha2:CGFloat  = 0
c2.getRed(&red2, green: &green2, blue: &blue2, alpha: &alpha2)


return (Int(green*255) == Int(green2*255))


}

这段代码不仅可以通过比较1而且可以通过比较所有组件来改进

这里有一个扩展,可以切换到 RGC 的 Swift 空间颜色:

extension UIColor {


func convertColorToRGBSpaceColor() -> UIColor {
let colorSpaceRGB = CGColorSpaceCreateDeviceRGB()
let oldComponents = CGColorGetComponents(self.CGColor)
let components = [oldComponents[0], oldComponents[0], oldComponents[0], oldComponents[1]]
let colorRef = CGColorCreate(colorSpaceRGB, components)
let convertedColor = UIColor(CGColor: colorRef!)
return convertedColor
}

}

我正在使用这个扩展,这是为我在所有情况下工作。

/***** UIColor Extension to Compare colors as string *****/
@interface UIColor (compare)
- (BOOL)compareWithColor:(UIColor *)color;
@end


@implementation UIColor(compare)
- (BOOL)compareWithColor:(UIColor *)color {
return ([[[CIColor colorWithCGColor:self.CGColor] stringRepresentation] isEqualToString:[[CIColor colorWithCGColor:color.CGColor] stringRepresentation]]);
}
@end
/**** End ****/

希望能帮助别人。

注意: 通过这个扩展,#ffffff等于 [UIColor whiteColor]

使用 Swift 2.2特性扩展到 UIColor。 然而,请注意,由于 R G B A 值是比较的,这些是 CGFloat,舍入错误可能使颜色不返回相等,如果他们不完全相同(例如,他们没有最初创建使用完全相同的属性在 init (...) .

/**
Extracts the RGBA values of the colors and check if the are the same.
*/


public func isEqualToColorRGBA(color : UIColor) -> Bool {
//local type used for holding converted color values
typealias colorType = (red : CGFloat, green : CGFloat, blue : CGFloat, alpha : CGFloat)
var myColor         : colorType = (0,0,0,0)
var otherColor      : colorType = (0,0,0,0)
//getRed returns true if color could be converted so if one of them failed we assume that colors are not equal
guard getRed(&myColor.red, green: &myColor.green, blue: &myColor.blue, alpha: &myColor.alpha) &&
color.getRed(&otherColor.red, green: &otherColor.green, blue: &otherColor.blue, alpha: &otherColor.alpha)
else {
return false
}
log.debug("\(myColor) = \(otherColor)")
//as of Swift 2.2 (Xcode 7.3.1), tuples up to arity 6 can be compared with == so this works nicely
return myColor == otherColor
}

UIColor 扩展

- (CGFloat)accuracyCompareWith:(UIColor *)color {
CIColor *c1 = [[CIColor alloc] initWithColor:self];
CIColor *c2 = [[CIColor alloc] initWithColor:color];


BOOL hasAlpha = c1.numberOfComponents == 4 && c2.numberOfComponents == 4;
NSInteger numberOfComponents = hasAlpha ? 4 : 3;


CGFloat colorMax = 1.0;
CGFloat p = colorMax / 100.0;


CGFloat redP = fabs(c1.red / p - c2.red / p);
CGFloat greenP = fabs(c1.green / p - c2.green / p);
CGFloat blueP = fabs(c1.blue / p - c2.blue / p);
CGFloat alphaP = 0;


if (hasAlpha)
alphaP = fabs(c1.alpha / p - c2.alpha / p);


return (redP + greenP + blueP + alphaP) / (CGFloat)numberOfComponents;
}

这个 UIColor 扩展可以很好地工作,只要比较的颜色可以转换成 RGB 格式,这应该是大多数情况下的格式。

public extension UIColor {


static func == (l: UIColor, r: UIColor) -> Bool {
var l_red = CGFloat(0); var l_green = CGFloat(0); var l_blue = CGFloat(0); var l_alpha = CGFloat(0)
guard l.getRed(&l_red, green: &l_green, blue: &l_blue, alpha: &l_alpha) else { return false }
var r_red = CGFloat(0); var r_green = CGFloat(0); var r_blue = CGFloat(0); var r_alpha = CGFloat(0)
guard r.getRed(&r_red, green: &r_green, blue: &r_blue, alpha: &r_alpha) else { return false }
return l_red == r_red && l_green == r_green && l_blue == r_blue && l_alpha == r_alpha
}
}

至少在这种情况下:

UIColor.whiteColor == UIColor(hex: "#FFFFFF") // true
UIColor.black == UIColor(red: 0, green: 0, blue: 0, alpha: 1) // true

如果使用本机 UColor.isequals (...)进行比较,则这两种比较都将返回 false

我已经将 Raf 的回答转换为 Swift 4(CGColor API 中的许多变化) ,由于大量使用了 guard,去除了力展开和减少了压痕:

@extension UIColor {
func isEqualToColor(otherColor: UIColor) -> Bool {
if self == otherColor {
return true
}
let colorSpaceRGB = CGColorSpaceCreateDeviceRGB()
let convertColorToRGBSpace: ((UIColor) -> UIColor?) = { (color) -> UIColor? in
guard color.cgColor.colorSpace?.model == .monochrome else {
return color
}
guard let oldComponents = color.cgColor.components else {
return nil
}
let newComponents = [oldComponents[0], oldComponents[0], oldComponents[0], oldComponents[1]]
guard let colorRef = CGColor(colorSpace: colorSpaceRGB, components: newComponents) else {
return nil
}
return UIColor(cgColor: colorRef)
}


guard let selfColor = convertColorToRGBSpace(self),
let otherColor = convertColorToRGBSpace(otherColor) else {
return false
}
return selfColor.isEqual(otherColor)
}
}

为什么不添加具有等效协议的扩展? 这个答案使用的是尼古拉斯 · 米亚里的解答。因此,如果你喜欢这个答案,请欢迎喜欢他的答案(从上到下第二个)

Zoul 的评论: 用这种方法比较颜色时要小心,因为它们必须在相同的颜色模型中才能被认为是相等的。例如,# ffffff 不等于[ UIColor whiteColor ]

static func == (lhs: UIColor, rhs: UIColor) -> Bool {


let colorSpaceRGB = CGColorSpaceCreateDeviceRGB()
let convertColorToRGBSpace: ((UIColor) -> UIColor?) = { (color) -> UIColor? in
guard color.cgColor.colorSpace?.model == .monochrome else {
return color
}
guard let oldComponents = color.cgColor.components else {
return nil
}
let newComponents = [oldComponents[0], oldComponents[0], oldComponents[0], oldComponents[1]]
guard let colorRef = CGColor(colorSpace: colorSpaceRGB, components: newComponents) else {
return nil
}
return UIColor(cgColor: colorRef)
}


guard let selfColor = convertColorToRGBSpace(lhs),
let otherColor = convertColorToRGBSpace(rhs) else {
return false
}
return selfColor.isEqual(otherColor)
}

虽然@samvermette 的回答非常好,但我发现当比较不同的颜色类型时(在我的例子中是 UIDeviceRGBColorUICachedDeviceWhiteColor) ,它有时会导致错误的否定。我通过显式地在“ else”中创建颜色来修复它:

- (BOOL)isEqualToColor:(UIColor *)otherColor
{
if (self == otherColor)
return YES;


CGColorSpaceRef colorSpaceRGB = CGColorSpaceCreateDeviceRGB();


UIColor *(^convertColorToRGBSpace)(UIColor*) = ^(UIColor *color)
{
if (CGColorSpaceGetModel(CGColorGetColorSpace(color.CGColor)) == kCGColorSpaceModelMonochrome)
{
const CGFloat *oldComponents = CGColorGetComponents(color.CGColor);
CGFloat components[4] = {oldComponents[0], oldComponents[0], oldComponents[0], oldComponents[1]};
CGColorRef colorRef = CGColorCreate(colorSpaceRGB, components);
UIColor *color = [UIColor colorWithCGColor:colorRef];
CGColorRelease(colorRef);
return color;
}
else
{
const CGFloat *oldComponents = CGColorGetComponents(color.CGColor);
CGFloat components[4] = {oldComponents[0], oldComponents[1], oldComponents[2], oldComponents[3]};
CGColorRef colorRef = CGColorCreate(colorSpaceRGB, components);
UIColor *color = [UIColor colorWithCGColor:colorRef];
CGColorRelease(colorRef);
return color;
}
};


UIColor *selfColor = convertColorToRGBSpace(self);
otherColor = convertColorToRGBSpace(otherColor);
CGColorSpaceRelease(colorSpaceRGB);


return [selfColor isEqual:otherColor];
}

你必须用

BOOL equalColors = CGColorEqualToColor(uiColor1.CGColor, uiColor2.CGColor));

文件 给你

我有一个类似的、但经过深思熟虑的、简洁明了的答案,很容易阅读和使用:

extension UIColor {
var rgba: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
var red = CGFloat.zero
var green = CGFloat.zero
var blue = CGFloat.zero
var alpha = CGFloat.zero
    

guard getRed(&red, green: &green, blue: &blue, alpha: &alpha) else {
debugPrint("color could not be retrieved")
return (1.0, 1.0, 1.0, 1.0)
}
return (red, green, blue, alpha)
}


static func == (lhs: UIColor, rhs: UIColor) -> Bool {
return  lhs.rgba == rhs.rgba
}
}

你可以这样使用它: (引自 Boherna)

UIColor.whiteColor == UIColor(hex: "#FFFFFF") // true
UIColor.black == UIColor(red: 0, green: 0, blue: 0, alpha: 1) // true