回答:
試しました[myColor isEqual:someOtherColor]
か?
ffffff
は等しくありません[UIColor whiteColor]
。
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];
}
UIColor *(^convertColorToRGBSpace)(UIColor*) = ^(UIColor *color) ...
はを宣言していblock
ます。彼は後でそれを使用しconvertColorToRGBSpace(self)
ます。iOSの中のブロックへのイントロは、以下を参照してくださいraywenderlich.com/9328/creating-a-diner-app-using-blocks-part-1
これは少し遅すぎるかもしれませんが、CoreGraphicsはこれを実現するためのより簡単なAPIを持っています。
CGColorEqualToColor(myColor.CGColor, [UIColor clearColor].CGColor)
ドキュメントのように:
2つの色が等しいかどうかを示します。2つの色は、色空間が等しく、色成分が数値的に等しい場合に等しくなります。
これにより、多くの問題とリーク/カスタムアルゴリズムが解決されます。
[UIColor isEqual:]
これと同じことをしませんか?マークの答えは、色空間にも関わらず同等性をチェックする唯一の答えです。
UIColor isEqual:
、色が異なる色空間にある場合と同じくらい役立ちます。
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
}
}
}
#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{
...
}
この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(...)を使用して比較すると、両方の比較でfalseが返されます。
私はこのカテゴリーを書きました。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
myimage.backgroundColor == [UIColor greenColor]
このステートメントの前にbackgroundColorを緑に変更していない場合にこのように比較すると、機能しません。
私のカラーゲームで同じ問題が発生し、RGBカラーの単純な差分方程式を使用して、ここから短いコードサンプルColorProcessをすばやく確認できます。
そのような勝利者が答えます
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)のようなものです。
いくつかの奇妙な丸めエラーが発生する可能性があります。オブジェクトが色に設定され、設定した色が正確に一致しないのは、このためです。
これは私がそれを解決した方法です:
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を比較するだけでなく、すべてのコンポーネントを比較することで改善できます。たとえば、red + green + blue + alpha == red2 + green2 + blue2 + alpha2
私はすべての場合に私のために働いているこの拡張機能を使用しています。
/***** 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で機能するアプローチは次のとおりです。
import CoreGraphics
extension UIColor {
/**
Checks for visual equality of two colors regardless of their color space.
- parameter color: The other color for comparison.
- returns: A boolean representing whether the colors are visually the same color.
*/
public func isVisuallyEqualTo(_ color: UIColor) -> Bool {
return rgbaComponents == color.rgbaComponents
}
public var rgbaComponents: [CGFloat] {
var data = [CUnsignedChar](repeating: 0, count: 4)
let colorSpace = CGColorSpaceCreateDeviceRGB()
let context = CGContext(data: &data,
width: 1, height: 1,
bitsPerComponent: 8, bytesPerRow: 4,
space: colorSpace,
bitmapInfo: CGImageAlphaInfo.noneSkipLast.rawValue)
context?.setFillColor(cgColor)
context?.fill(CGRect(x: 0, y: 0, width: 1, height: 1))
return data.map { CGFloat($0) / 255.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);
}
-1
呼び出した後もこの値が残っているgetRed:green:blue:alpha:
場合は、比較が失敗したことがわかります。(または、正常に呼び出されたかどうかがわかるので、返されたブール値を省略しないでください。)
getRed:free:blue:alpha:
、モノクロでは成功しないため、コードでは機能しません。したがって、コードは以外の結果を生成しませんis equal:
。それへの対処方法については私の回答をご覧ください。
SwiftでRGC Space Colorに切り替える拡張機能を次に示します。
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
}
}
Swift 2.2機能を使用したUIColorの拡張。ただし、RGBA値が比較され、これらが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;
}
私は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)
}
}
Equatableプロトコルを使用して拡張機能を追加しないのはなぜですか?この答えはニコラス・ミアリの解決策を使用しています。だから、この答えが好きなら、彼の答えを好きに歓迎してください(上から2番目)
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の答えは非常に良いですが、異なる色のタイプ(私の場合UIDeviceRGBColor
はUICachedDeviceWhiteColor
)を比較すると、誤ったネガティブになることがあります。私も明示的に「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];
}