2009-06-09 2 views
115

Я хотел бы проверить набор цветов для фона на UIImageView. Я пробовал:Как сравнить UIColors?

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

но это не работает, даже если я знаю, что цвет зеленый, он всегда попадает в другую часть.

Также есть способ вывода текущего цвета в консоли отладки.

p [myimage backgroundColor] 

и

po [myimage backgroundColor] 

не работают.

ответ

168

Вы пробовали [myColor isEqual:someOtherColor]?

+0

Спасибо. В чем разница с isEqualTo? Кроме того, знаете ли вы, как отображать его в отладчике? – 4thSpace

+81

Кстати: будьте осторожны при сравнении цветов таким образом, потому что они должны быть в одной и той же цветовой модели, которая считается равной. Например, # 'ffffff' не равно' [UIColor whiteColor] '. – zoul

+2

Хорошая точка Zoul, может быть более полезно указать на решение не только проблемы, хотя = D – pfrank

-1
if([myimage.backgroundColor isEqual:[UIColor greenColor]]) 
+0

Но это лучше, чем некоторые другие ответы здесь. –

70

Как Zoul отметил в комментариях, isEqual: вернется NO при сравнении цвета, которые находятся в разных моделях/пространствах (например, #FFF с [UIColor whiteColor]). Я написал это расширение 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]; 
} 
+2

Ничего, но есть утечка, я думаю. Вы никогда не выпускаете CGColorCreate посередине. – borrrden

+0

Это идеальное решение! – alones

+0

Хорошо работает – htafoya

7
#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{ 
... 
} 
+1

, что репо сейчас находится в https://github.com/thetaplab/uicolor-utilities – PapaSmurf

+4

Это нечитабельно. –

+0

@ Рудольф Адамкович, это теорема Пифагора –

2

Когда вы сравниваете myimage.backgroundColor == [UIColor greenColor] как это, если вы Havent изменить BackgroundColor к зеленому до этого заявления не работает.

У меня была такая же проблема в моей цветовой игре, и я решил, что с помощью простого разностного уравнения в RGB цветов вы можете быстро взглянуть, что короткий пример кода ColorProcess от here

его как победители ответ

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.0f - 1.5f) ..

+0

color.red/blue/green не поддерживаются для всех типов классов цветов, проверьте документы – pfrank

0

насчет:

+(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); 
} 
+0

, это может не работать для случаев кромок в качестве цвета шаблона. from doc * Если цвет находится в совместимом цветовом пространстве, цвет преобразуется в формат RGB, а его компоненты возвращаются в ваше приложение. Если цвет не соответствует совместимому цветовому пространству, параметры не изменяются. * Таким образом, вы можете создать экземпляр каждого поплавка с '-1', и если у него все еще есть это значение после вызова' getRed: green: blue: alpha: ', вы знаете сравнение не удалось. (или не опускайте возвращаемое логическое значение, поскольку оно скажет вам, было ли это вызвано успешно.) – vikingosegundo

+1

Я только что проверил: хотя теоретически можно проверить монохромность цветов RGBA, это не сработает с вашим кодом, так как ' getRed: бесплатно: синий: alpha: 'не удастся на монохромном цвете. Таким образом, ваш код не даст другого результата, чем 'равно:'. см. мой ответ, как с этим бороться. – vikingosegundo

+0

+1 для тщательности! Вышеприведенный код работает для моего простого случая, но, похоже, это не серебряная пуля. Хорошая вещь. – dooleyo

5

Я написал эту категорию. Если 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 
54

Это может быть немного слишком поздно, но CoreGraphics имеет более простой API для достижения этой цели:

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

Как документации говорит:

Указывает равны ли два цвета. Два цвета равны, если они имеют одинаковые цветовые пространства и числовые равные цветовые компоненты.

Это решает много проблем и утечек/пользовательских алгоритмов. Решение

+0

Это должен быть принятый ответ. – aleclarson

+3

'[UIColor isEqual:]' делает то же самое, что и это, не так ли? Ответ Марка по-прежнему остается единственным, который проверяет эквивалентность, несмотря на цветовое пространство. – mattsven

+4

Это не больше, чем 'UIColor isEqual:' если цвета находятся в разных цветовых пространствах. – Echelon

7

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 
     } 
    } 
} 
0

Некоторые странные ошибки округления. Это может быть причиной того, что объект установлен на цвет, а цвет, который вы ему установили, не соответствует точно.

Это, как я ее решил:

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, но сравнивая все компоненты. Например, красный + зеленый + синий + альфа == Red2 + Green2 + blue2 + альфа2

+1

Цвета не совпадают, если сравнивать только с зеленым компонентом – Andy

+0

Это единственный ответ, который упоминает и пытается устранить потенциальные ошибки округления, которые могут возникать при сравнении цветов, которые устанавливаются различными способами; поэтому, в то время как он фокусируется только на зеленом, пример (как автор ответа упоминает) может быть обобщен. Таким образом, и поскольку округление было на самом деле проблемой, с которой я столкнулся, я нашел этот ответ полезным. –

0

Вот расширение, чтобы переключиться на RGC Space Цвет в 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 
} 

}

1

Я используя это расширение, которое работает для меня во всех случаях.

/***** 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] этим расширением

+0

Это работает при сравнении цветов в цветовых пространствах? –

+0

Не уверен, я не тестировал его для всех цветовых пространств. – arunit21

0

Extension к UIColor, используя Swift 2.2 функции. Обратите внимание, что, поскольку значения RGBA сравниваются, и это CGFloat, ошибки округления могут привести к тому, что цвета не будут возвращены как равные, если они не совсем одинаковы (например, они изначально не были созданы с использованием тех же свойств в в этом(...)!).

/** 
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 
} 
0

расширение 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; 
} 
1

Это расширение 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.isEqual (...)

Смежные вопросы