2013-03-08 11 views
5

Ho cercato di replicare il gradiente da UINavigationBar da utilizzare come gradiente sugli oggetti di sottoclasse personalizzati UIButton nella stessa vista.Come posso replicare i colori del gradiente di UINavigationBar?

Tuttavia, non riesco a capire come vengono derivati ​​i colori? Cioè, si specifica solo un colore per impostare il colore di sfondo di - ma crea un gradiente gradevole con almeno 4 colori?

Mi interessano solo i colori "interni" e quelli inferiori, solo all'interno del bordo 1px attorno alla barra ... i colori esterni "bordo" appaiono in effetti diversi.

EDIT - 1

Dopo ulteriori ricerche, sembra che il HSB (invece del RBG come primo pensiero) i valori sono manipolati per ottenere questi colori differenti.

V'è anche un metodo comodo sulla UIColor per ottenere i valori HSB, che dovrebbe essere utile:

getHue:saturation:brightness:alpha: 

Riferimenti utili trovato finora

HSL and HSV Wiki

UIColor Class Reference

Programmatically Lighten a Color

From the book Fundamentals of Interactive Computer Graphics

EDIT - 2

Nel caso in cui non erano a conoscenza che è possibile impostare un gradiente per uno sfondo su un UIButton di programmazione, ecco alcuni riferimenti su come fare, quali:

FUN WITH UIBUTTONS AND CORE ANIMATION LAYERS

Five Tips for Creating Stylish UIButtons (kudos to @ cdo per fornire questo collegamento)

EDIT - 3

Ho messo insieme un foglio di calcolo che mostra la i colori "interni" gradiente originale e (trascurando la maggior parte dei colori esterni) in valori HSB su UINavigationBar e il suo corrispondente pulsante "indietro" (titoli sono irrilevanti e sempre visualizzati in bianco).

Ecco un link al documento Google con le informazioni che ho raccolto per alcuni colori a campione:

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

Nota: questi valori sono stati trovati salvando uno screenshot con la retina, 3.5" iPhone Simulator (Xcode versione 4.6) per iOS 6.1 e distorsione dei valori HSB con PhotoShop.

BOUNTY CRITERI DI AGGIUDICAZIONE

Ho aperto una taglia su questo problema per portare più l'esposizione ad esso e si spera ottenere una buona risposta. La risposta che sto cercando:

Fornire un metodo di calcolo/strettamente approssimativo (nella maggior parte dei casi) dei valori RGB o HSB dei colori del gradiente "inner top" e "bottom bottom" (vedere foglio di calcolo) creati dopo impostazione di tintColor su UINavigationBar.

Punti bonus assegnati (oltre l'offerta di taglie iniziale) se si fornisce anche un metodo per calcolare i colori sfumati "superiore interno" e "fondo interno" sul pulsante "indietro" (che è simile alla barra di navigazione, ma io hai trovato questi colori leggermente "più scuri" di solito)?

+0

troppo tardi per la generosità, ma si spera che qualcuno troverà la mia risposta utile in ogni caso ... – danh

risposta

7

Risposta breve: non è gradiente

lungo Risposta: Dopo colore della tinta applicata, v'è una sovrapposizione di immagini trasparente reso su di esso.

Si chiama: [email protected] e si trova nella grafica UIKit. (caricato qui: http://cl.ly/image/2c2V3t1D1T3L)

L'immagine è di 2x88 pixel e deve essere ripetuta orizzontalmente su uno sfondo colorato.

Per il pulsante Indietro, è molto simile, ma c'è anche una maschera per dargli la forma. UItintedBackButtonHighlight e UITintedBackButtonMask.

+1

Dove/come hai trovato questa immagine? –

+0

Per rispondere alla mia domanda, questo è utile: https://github.com/0xced/UIKit-Artwork-Extractor –

+0

Questa è la soluzione con cui sono andato. Nel mio caso, ho creato un gradiente di immagine più grande (maggiore altezza) che viene aggiunto come sovrapposizione per i pulsanti. Assegnerò la taglia quando il limite di tempo di taglia è passato. –

0

UIButton accetta una singola proprietà tintColor ma ciò non significa che non importi altri colori da utilizzare nel gradiente dietro le quinte. Try this tutorial.

+0

Grazie per il vostro contributo, ma questa risposta è fuorviante e onestamente non corretta ...(1) 'tintColor' imposta il colore * su premuto *, che è un colore ** solido ** (non sfumato), (2) c'è una proprietà' backgroundColor' su 'UIButton', che viene applicata correttamente se il tipo di pulsante è 'UIButtonTypeCustom' ma è ancora un colore a tinta unita e (3) sì, il collegamento del tutorial sarebbe utile se si tentasse di applicare gradienti a un pulsante (che ** deve ** essere eseguito aggiungendo un livello sfumatura, a mia conoscenza) ma il problema è che questo non aiuta a determinare i colori corretti per simulare il gradiente della barra di navigazione. –

+0

Posso vedere, forse, come la domanda potrebbe essere fuorviante perché sia ​​'UIButton' che' UINavigationBar' hanno effettivamente proprietà 'tintColor', quindi ho modificato la domanda per renderla più chiara. Grazie ancora per il tuo contributo. –

+0

+1 Per il collegamento ... L'ho anche aggiunto come modifica alla domanda –

2

È difficile copiare il comportamento esatto perché sembra che Apple stia calcolando diversi per diversi gruppi di colori. per esempio. un colore chiaro è leggermente oscurato mentre si illumina un colore scuro.

Uguale per la voce del pulsante della barra. Per alcuni colori la differenza tra il normale pulsante "bordato" e il pulsante "finito" è completamente diversa. A volte non apprezzabile come per il turchese ma decisamente avvincente per l'arancione.

Per la creazione di questo codice di esempio ho usato PaintCode un bel strumento per la prototipazione btw ..
Copia questo codice in una sottoclasse UIView o qualcosa del genere. O semplicemente prendi il codice pezzi che ti serve.

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

Inizialmente ho avuto questa idea (cambiando i valori RGB), ma non penso che Apple lo faccia in questo modo (suppongo che siano cambia i valori HSB - saturazione e luminosità in modo specifico). Comunque, +1 come sembra * simile * ... spero comunque di avvicinarmi un po 'ai colori di Apple. –

+0

Ho davvero provato a manipolare la tonalità, la sicurezza e la luminosità, ma il risultato non è stato bello come questo. (basta caricare l'app demo e provarla per te, ha il tipo di manipolazione di sottocolore desiderata, ad esempio turquite e orange non possono essere gestiti con la stessa manipolazione della saturazione). E ancora, sembra che Apple usi calcoli diversi per un mucchio di colori. –

2

Grazie per la bella domanda e la generosa generosità. Sono andato a lavorare su questo e ho trascurato di fare il check-in per vedere che la risposta era già accettabile. Tuttavia, è stato divertente costruzione e collaudo della categoria barra di navigazione, che rivela i suoi colori ...

// 
// 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 

Collegamento 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 red = 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:red 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 

chiamare in questo modo:

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

+1: soluzione Neat - interrogazione della barra di navigazione a livello di programmazione. –

+0

grazie. :-) realizzato dopo la pubblicazione che potrebbe facilmente essere una categoria UIView, rispondendo a qualsiasi colore in qualsiasi posizione da qualsiasi vista. basta cambiare UINavigationBar (colori) in UIView (colori). – danh

Problemi correlati