¿Cómo puedo replicar los colors degradados de UINavigationBar?

He estado intentando replicar el degradado de UINavigationBar para utilizarlo como un degradado en objects de subclass UIButton personalizados en la misma vista.

Sin embargo, no puedo entender cómo se derivan los colors. Es decir, solo se especifica un color para establecer un UINavigationBar de background de tintColortintColor – pero crea un bonito gradiente con al less 4 colors.

Realmente solo me interesan los colors superior e inferior "internos", solo dentro del borde de 1px alnetworkingedor de la barra … los colors "de borde" exteriores ciertamente parecen diferentes.

EDITAR – 1

Luego de más investigaciones, parece que los HSB (en lugar del RBG, como se pensó inicialmente) están manipulando los valores para get estos diferentes colors.

También hay un método de conveniencia en UIColor para get los valores de HSB, lo que debería ser útil:

 getHue:saturation:brightness:alpha: 

Referencias útiles encontradas hasta ahora

HSL y HSV Wiki

Referencia de class UIColor

Progtwigr aligerar un color

Del libro Fundamentos de charts interactivos para computadora

EDITAR – 2

En caso de que no UIButton que puede establecer un degradado para un background en un UIButton progtwigción, aquí hay algunas references sobre cómo hacerlo:

DIVERSIÓN CON UIBUTTONS Y CAPAS DE ANIMACIÓN BÁSICA

Cinco consejos para crear UIButtons con estilo (felicitaciones a @cdo por proporcionar este enlace)

EDITAR – 3

UINavigationBar una spreadsheet que muestra los colors originales y gradientes "internos" (sin tener en count la mayoría de los colors exteriores) en los valores de HSB en UINavigationBar y su correspondiente button "atrás" (los títulos son irrelevantes y siempre se muestran en blanco).

Aquí hay un enlace al documento de Google con la información que recopilé para algunos colors de ejemplo:

https://docs.google.com/spreadsheet/ccc?key=0AnKVtzkNS9scdGVRN01pa1NQcC1hdThNbEVzQU8wRlE&usp=sharing

Nota: estos valores se encontraron guardando una captura de pantalla usando la retina, 3.5 "iPhone Simulator (Xcode versión 4.6) para iOS 6.1 y dejando caer los valores de HSB usando PhotoShop.

CRITERIOS DEL PREMIO BOUNTY

He abierto una recompensa en esta pregunta para traer más exposition a ella y espero get una buena respuesta. La respuesta que estoy buscando:

Proporcionar un método de cálculo / aproximación aproximada (en la mayoría de los casos) de los valores RGB o HSB de los colors de degradado "interior superior" e "background interior" (ver spreadsheet) creados después de configurar un tintColor en UINavigationBar .

Se otorgarán puntos de bonificación (por encima de la oferta inicial de recompensas) si también proporciona un método para calcular los colors de degradado "parte superior interna" e "parte inferior interna" en el button "atrás" (que es similar a la barra de navigation, pero los he encontrado los colors parecen ser ligeramente "más oscuros" por lo general)?

Respuesta corta: no está degradado

Respuesta larga: después de aplicar el color de tinte, hay una image de superposition transparente representada en la parte superior.

Se llama: UITintedTopBarHighlight@2x.png y está en la ilustración de UIKit. (subido aquí: http://cl.ly/image/2c2V3t1D1T3L )

Es una image de 2×88 píxeles, y debe repetirse horizontalmente sobre background polarizado.

Para el button de retroceso, es muy similar, pero también hay una máscara para darle forma. UItintedBackButtonHighlight y UITintedBackButtonMask.

Es difícil copyr el comportamiento exacto porque parece que Apple está calculando diferente para diferentes grupos de colors. p.ej. un color claro se oscurece ligeramente mientras que se ilumina un color oscuro.

Lo mismo para el elemento del button de barra. Para algunos colors, la diferencia para el button "borde" normal y el button "estilo" es completamente diferente. A veces no se nota como en turquesa pero definitivamente se puede ver en naranja.

Para crear este código de ejemplo, usé PaintCode como una buena herramienta para crear prototypes, por cierto.
Copie este código en una subclass UIView o algo así. O simplemente agarra el código de piezas que necesitas.

 - (void)drawRect:(CGRect)rect { //// General Declarations CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGContextRef context = UIGraphicsGetCurrentContext(); //// Color Declarations UIColor* tint = [UIColor colorWithRed: 1 green: 0.66 blue: 0.329 alpha: 1]; CGFloat tintRGBA[4]; [tint getRed: &tintRGBA[0] green: &tintRGBA[1] blue: &tintRGBA[2] alpha: &tintRGBA[3]]; UIColor* lighter = [UIColor colorWithRed: (tintRGBA[0] * 0.58 + 0.42) green: (tintRGBA[1] * 0.58 + 0.42) blue: (tintRGBA[2] * 0.58 + 0.42) alpha: (tintRGBA[3] * 0.58 + 0.42)]; CGFloat lighterRGBA[4]; [lighter getRed: &lighterRGBA[0] green: &lighterRGBA[1] blue: &lighterRGBA[2] alpha: &lighterRGBA[3]]; UIColor* lightest = [UIColor colorWithRed: (lighterRGBA[0] * 0.55 + 0.45) green: (lighterRGBA[1] * 0.55 + 0.45) blue: (lighterRGBA[2] * 0.55 + 0.45) alpha: (lighterRGBA[3] * 0.55 + 0.45)]; UIColor* darker = [UIColor colorWithRed: (tintRGBA[0] * 0.92) green: (tintRGBA[1] * 0.92) blue: (tintRGBA[2] * 0.92) alpha: (tintRGBA[3] * 0.92 + 0.08)]; CGFloat darkerRGBA[4]; [darker getRed: &darkerRGBA[0] green: &darkerRGBA[1] blue: &darkerRGBA[2] alpha: &darkerRGBA[3]]; UIColor* darkest = [UIColor colorWithRed: (darkerRGBA[0] * 0.65) green: (darkerRGBA[1] * 0.65) blue: (darkerRGBA[2] * 0.65) alpha: (darkerRGBA[3] * 0.65 + 0.35)]; //// Gradient Declarations NSArray* gradientColors = [NSArray arrayWithObjects: (id)lighter.CGColor, (id)darker.CGColor, nil]; CGFloat gradientLocations[] = {0, 1}; CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)gradientColors, gradientLocations); //// top Drawing UIBezierPath* topPath = [UIBezierPath bezierPathWithRect: CGRectMake(0, 0, rect.size.width, 1)]; [lightest setFill]; [topPath fill]; //// theGradient Drawing UIBezierPath* theGradientPath = [UIBezierPath bezierPathWithRect: CGRectMake(0, 1, rect.size.width, rect.size.height - 1.0f)]; CGContextSaveGState(context); [theGradientPath addClip]; CGContextDrawLinearGradient(context, gradient, CGPointMake(50, 1), CGPointMake(50, rect.size.height-1.0f), 0); CGContextRestoreGState(context); //// bottom Drawing UIBezierPath* bottomPath = [UIBezierPath bezierPathWithRect: CGRectMake(0, rect.size.height-1.0f, rect.size.width, 1)]; [darkest setFill]; [bottomPath fill]; //// Cleanup CGGradientRelease(gradient); CGColorSpaceRelease(colorSpace); } 

Gracias por la buena pregunta y la generosa generosidad. Me puse a trabajar en esto y me olvidé de registrarme para ver que ya había sido respondida de forma aceptable. Sin embargo, fue divertido crear y probar la siguiente categoría de barra de navigation, que revela sus colors …

 // // UINavigationBar+colors.h #import <UIKit/UIKit.h> @interface UINavigationBar (Colors) // Answer an array of colors representing the color of the reciever, starting at fromY, up to toY - (NSArray *)colorsFromY:(NSUInteger)fromY to:(NSUInteger)toY; @end 

Enlace con QuartzCore.framework.

 // // UINavigationBar+colors.m #import "UINavigationBar+colors.h" #import <QuartzCore/QuartzCore.h> #define UIIMAGE_BYTES_PER_PIXEL 4u @implementation UINavigationBar (Colors) + (NSData *)dataFromImage:(UIImage *)image { CGImageRef imageRef = [image CGImage]; NSUInteger width = CGImageGetWidth(imageRef); NSUInteger height = CGImageGetHeight(imageRef); CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); NSUInteger dataSize = height * width * UIIMAGE_BYTES_PER_PIXEL; unsigned char *rawData = malloc(dataSize); NSUInteger bytesPerRow = width * UIIMAGE_BYTES_PER_PIXEL; NSUInteger bitsPerComponent = 8; CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); CGColorSpaceRelease(colorSpace); CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef); CGContextRelease(context); NSData *rtn = [NSData dataWithBytes:rawData length:dataSize]; free(rawData); return rtn; } + (UIColor *)colorOfImage:(UIImage *)image atX:(NSUInteger)px atY:(NSUInteger)py { NSData *imgData = [self dataFromImage:image]; if (!imgData) return nil; NSUInteger byteIndex = UIIMAGE_BYTES_PER_PIXEL * (image.size.width * py + px); unsigned char rgbaData[4]; NSRange range = { byteIndex, 4u }; [imgData getBytes:rgbaData range:range]; CGFloat networking = rgbaData[0] / 255.0; CGFloat green = rgbaData[1] / 255.0; CGFloat blue = rgbaData[2] / 255.0; CGFloat alpha = rgbaData[3] / 255.0; return [UIColor colorWithRed:networking green:green blue:blue alpha:alpha]; } - (UIImage *)asImage { UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.opaque, 0.0); [self.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage * img = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return img; } - (NSArray *)colorsFromY:(NSUInteger)fromY to:(NSUInteger)toY { NSMutableArray *answer = [NSMutableArray array]; UIImage *image = [self asImage]; for (NSUInteger y = MAX(0, fromY); y < MIN(self.bounds.size.height, toY); y++) { [answer addObject:[self.class colorOfImage:image atX:1 atY:y]]; } return [NSArray arrayWithArray:answer]; } @end 

Llámalo así:

 // from a view controller contained by a navigation controller... UINavigationBar *bar = self.navigationController.navigationBar; NSArray *colors = [bar colorsFromY:0 to:bar.bounds.size.height]; for (UIColor *color in colors) { NSLog(@"%@", color); } 

UIButton toma una sola propiedad tintColor , pero eso no significa que no esté calculando otros colors para usar en el gradiente detrás de escena. Prueba este tutorial .