2012-05-11 9 views
13

Recentemente mi sono imbattuto in questo brillante articolo sul miglioramento delle prestazioni di scorrimento con UITableViewCells: http://engineering.twitter.com/2012/02/simple-strategies-for-smooth-animation.html - Mentre in questo articolo sono disponibili molti ottimi consigli, ce n'è uno in particolare che mi ha incuriosito :CoreGraphics - Blending only * part * of a view

I tweet in Twitter per iPhone 4.0 hanno un'ombra esterna su uno sfondo a trama sottile. Questo ha rappresentato una sfida, poiché la miscelazione è costosa. Abbiamo risolto questo problema riducendo l'area che Core Animation deve considerare non opaca, dividendo le aree d'ombra dall'area del contenuto della cella.

Utilizzando il simulatore iOS, cliccando Debug - colori Blended strati avrebbero rivelato qualcosa di simile:

TwitterTableViewCell

Le aree contrassegnate in rosso si fondono, e la zona verde è opaco. Grande. Quello che l'articolo non menziona è: come posso implementarlo? A quanto mi risulta, un UIView è opaco o non lo è. Mi sembra che l'unico modo per ottenere questo risultato sarebbe con subviews, ma l'articolo afferma esplicitamente che come un'implementazione ingenuo:

Invece, le nostre cellule Tweet contengono una singola vista senza subviews; un singolo drawRect: disegna tutto.

Quindi, come faccio a troncare ciò che è opaco, e cosa non c'è nel mio singolo drawRect: metodo?

+0

inviare loro una e-mail o twittare con la domanda: p riporto a SO quando si ottiene una risposta :) – haroldcampbell

+0

Raggiunto a loro tramite Twitter: http://bit.ly/LK7lvs - si spera che possiamo ottenere il * right * answer :) – nrj

+0

@nick Hai ancora una risposta? Sono sinceramente interessato Questa è stata una domanda fantastica e mi piacerebbe sapere se c'è un modo per rendere trasparente solo una parte di una vista. –

risposta

3

Nell'esempio che mostri, non credo che stiano mostrando uno sfondo attraverso la vista. Penso che stiano simulando uno sfondo nella core graphics. In altre parole, in ciascuna cella disegnano un colore grigio chiaro per lo sfondo. Poi disegnano l'ombra (usando la trasparenza) e infine disegnano il resto del contenuto opaco in alto. Potrei sbagliarmi, ma non credo che tu possa rendere trasparenti porzioni della vista. Se è così, sarei molto, molto interessato a questo, perché io uso sempre la grafica di base, ma evito gli angoli arrotondati perché non è valsa la pena di unire l'intera vista per esso.

Aggiornamento

Dopo aver fatto qualche ricerca più e guardando attraverso documenti di Apple, non credo che sia possibile solo per una parte di una visione per essere opaco. Inoltre, dopo aver letto il post sul blog di Twitter, non penso che stiano dicendo che lo hanno fatto. Si noti che quando si dice:

Invece, le nostre celle Tweet contengono una vista singola senza visualizzazioni secondarie; un singolo drawRect: disegna tutto.

Stavano specificatamente parlando di UILabel e UIImageView. In altre parole, invece di usare quelle viste stanno disegnando l'immagine direttamente usando Core Graphics. Per quanto riguarda gli UILabels, io personalmente utilizzo il Core Text poiché ha più supporto per i font, ma potrebbe anche usare qualcosa di più semplice come il metodo drawAtPoint:withFont: di NSString. Ma il punto principale che stanno cercando di trasmettere è che il contenuto della cella è tutto un disegno in CG.

Quindi si spostano in una nuova sezione: Evita la fusione. Qui si dice che evitano di mescolare:

dividendo le aree d'ombra dall'area di contenuto della cella.

L'unico modo per fare ciò è utilizzare viste diverse. Esistono due approcci che potrebbero essere utilizzati, ma innanzitutto si noti che i divisori di celle sono essi stessi sovrapposizioni (forniti da tableView). Il primo modo è utilizzare più viste all'interno della cella. Il secondo modo è di sovrapporre/sovrapporre le ombre/le viste miste dietro/sopra le celle inserendo le viste appropriate in UIScrollView. Data la loro precedente affermazione sull'avere solo una vista/drawRect per ogni cella, questo è probabilmente quello che stanno facendo. Ogni metodo avrà le sue sfide, ma personalmente penso che sarebbe più facile dividere la cella in 3 viste (ombra, contenuto, ombra). Renderebbe molto più semplice gestire situazioni di prima/ultima cella.

+0

Certo che posso disegnare sfumature e colori trasparenti, ma nella cella Tweet le ombre sono sui bordi e lasciano trasparire lo sfondo. Ciò implica che la vista in cui li sto disegnando è * non * opaca, altrimenti vedresti uno sfondo nero dietro le ombre invece della vista dietro di loro. – nrj

+0

Non penso che stiano mostrando attraverso uno sfondo. Penso che stiano simulando uno sfondo nella loro vista cella. Aggiornerò la mia risposta per spiegare. –

+0

L'articolo afferma: "I tweet hanno un'ombra esterna su uno sfondo a trama sottile, che ha presentato una sfida, poiché la fusione è costosa." - Se stanno solo * simulando * uno sfondo, allora non avrebbero bisogno di fondere nulla e l'intera vista della cella sarebbe verde quando si attiva "Livelli colorati". – nrj

0

avrei dovuto intuire qualcosa in questo senso
http://developer.apple.com/library/mac/#documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_shadows/dq_shadows.html

CGContextRef context = UIGraphicsGetCurrentContext(); 

UIBezierPath* path = [UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:10.0f]; 

CGContextSaveGState(context); 
CGRect leftRect = CGRectZero; 
CGContextClipToRect(context, leftRect); 
CGContextSetBlendMode(context, kCGBlendModeNormal); 
// draw shadow 

// Call the function CGContextSetShadow, passing the appropriate values. 
// Perform all the drawing to which you want to apply shadows. 
CGContextSetShadowWithColor(context, CGSizeMake(1.0f, 1.0f), 10.0f, [UIColor blackColor].CGColor); 
CGContextAddPath(context, path.CGPath); 
CGContextDrawPath(context, kCGPathStroke); 


CGContextRestoreGState(context); 

CGContextSaveGState(context); 
CGRect middleSection = CGRectZero; 
CGContextClipToRect(context, middleSection); 
CGContextSetFillColorWithColor(context, self.backgroundColor.CGColor); 
CGContextFillRect(context, self.bounds); 
// draw opaque 
CGContextSetBlendMode(context, kCGBlendModeCopy); 

CGContextRestoreGState(context); 
+0

Nella cella Tweet sopra, l'ombra si trova lungo il lato sinistro e destro della vista, sopra un'altra vista di sfondo. Posso usare questo codice per disegnare un'ombra, ma se non faccio '[cell setOpaque: NO]' ci sarà uno sfondo nero dietro l'ombra. Quello che voglio è che la vista di sfondo sia visibile. – nrj

+0

Rende l'immagine di sfondo, l'ombra di ritaglio/di ritaglio a sinistra, l'ombra di ritaglio/di ritaglio a destra, il rendering di primo piano. – Nico

+0

inoltre potresti volere kCGBlendModeScreen invece della normale miscela. – Nico

0

La mia opinione è: Non lasciate Core Animation disegnare ombre utilizzando i vari layer properties. Basta disegnare un'immagine prerenderata su entrambi i lati, che di fatto è un'ombra. Per calcolare l'altezza variabile di una cella in un stretch draw può fare il trucco.

MODIFICA: Se lo sfondo è chiaro, un'ombra prerender può essere applicata su entrambi i lati senza che ciò influisca sul fascino visivo.

Nel caso in cui non sia applicabile, la vista tabella deve essere ridotta per essere della dimensione senza l'ombra. Quindi l'ombra può essere miscelata senza farlo per ogni cella ma solo "sopra". Non scorre davvero. Questo funzionerà solo se l'ombra è priva di "texture", altrimenti si noterà che è solo applicata sopra.

+0

Non importa come disegni l'ombra. Affinché lo sfondo sia visibile attraverso di esso, l'intera vista dovrebbe essere impostata su non opaco. – nrj

+0

È importante, penso di non averlo descritto abbastanza correttamente. Se lo sfondo è statico, non devi mescolarlo, quindi un'ombra prerenderata, già miscelata con uno sfondo statico, è solo disegno senza fusione. Si prega di consultare la mia modifica. –

+0

Sì. Mi rendo conto che questo particolare esempio potrebbe essere eseguito senza miscelazione. Vedi il commento di Aaron sopra appena su come simulare lo sfondo. La mia domanda non è "come creo questa cella", ci sono diversi modi per farlo. Voglio sapere come sono stati in grado di fondere solo una sezione della vista senza contrassegnare l'intera vista come non opaca e senza utilizzare le visualizzazioni secondarie. Imparare a farlo potrebbe essere molto utile in altre situazioni in cui il disegno di uno sfondo statico non è un'opzione. – nrj