CoreGraphics: mezcla solo * parte * de una vista

Hace poco me encontré con este shiny artículo sobre la mejora del performance de desplazamiento con UITableViewCells: http://engineering.twitter.com/2012/02/simple-strategies-for-smooth-animation.html – Aunque se pueden encontrar muchos consejos excelentes en esto artículo, hay uno en particular que me intrigó:

Tweets en Twitter para iPhone 4.0 tienen una sombra sobre un sutil background texturado. Esto representó un desafío, ya que la mezcla es cara. Resolvimos esto networkinguciendo el área que Core Animation debe considerar no opaca, dividiendo las áreas de sombra del área de contenido de la celda.

Al usar el simulador de iOS, hacer clic en DebugColor Blended Layers revelaría algo como esto:

TwitterTableViewCell

Las áreas marcadas en rojo se mezclan, y el área verde es opaca. Estupendo. Lo que el artículo no menciona es: ¿Cómo implemento esto? Entiendo que una UIView es opaca o no lo es. Me parece que la única forma de lograr esto sería con las subvenciones, pero el artículo dice explícitamente que como una implementación ingenua :

En cambio, nuestras celdas Tweet contienen una única vista sin subidas; un solo drawRect: dibuja todo.

Entonces, ¿cómo puedo separar lo opaco y lo que no está en mi único método drawRect: método?

En el ejemplo que muestra, no creo que muestren un background a través de la vista. Creo que están simulando un background en charts centrales. En otras palabras, en cada celda dibujan un color gris claro para el background. Luego dibujan la sombra (usando transparencia), y finalmente dibujan el rest del contenido opaco en la parte superior. Podría estar equivocado, pero no creo que puedas hacer que las partes de la vista sean transparentes. Si es así, estaría muy, muy interesado en él porque uso los charts centrales todo el time, pero evito las esquinas networkingondeadas porque mezclar la vista completa simplemente no parece valer la pena.

Actualizar

Después de hacer un poco más de investigación y mirar a través de los documentos de Apple, no creo que sea posible que solo una parte de la vista sea opaca. Además, después de leer la publicación del blog de Twitter, no creo que digan que lo hicieron. Tenga en count que cuando dicen:

En cambio, nuestras celdas Tweet contienen una única vista sin subidas; un solo drawRect: dibuja todo.

Estaban hablando específicamente de UILabel y UIImageView . En otras palabras, en lugar de usar esas vistas, están dibujando la image directamente usando Core Graphics. En cuanto a UILabels, personalmente utilizo Core Text ya que tiene más soporte de fonts, pero también pueden estar usando algo más simple como drawAtPoint:withFont: method de drawAtPoint:withFont: . Pero el punto principal al que intentan llegar es que el contenido de la celda es todo un dibujo CG.

Luego se mudan a una nueva sección: Evita mezclar . Aquí hacen un punto de decir que evitan mezclarse por:

dividir las áreas de sombra del área de contenido de la celda.

La única forma de hacerlo es usar diferentes vistas. Hay dos enfoques que podrían usar, pero primero tenga en count que los divisores de celdas son superposiciones de sí mismos (provistos por tableView). La primera forma es usar varias vistas dentro de la celda. La segunda forma es subponer / superponer las sombras / vistas mezcladas detrás / sobre las celdas insertando las vistas apropiadas en el UIScrollView. Teniendo en count su statement anterior sobre tener solo una vista / drawRect para cada celda, esto es probablemente lo que están haciendo. Cada método tendrá sus desafíos, pero personalmente creo que sería más fácil dividir la celda en 3 vistas (sombra, contenido, sombra). Sería mucho más fácil manejar situaciones de primera / última célula.

Tendría que adivinar algo a lo largo de estas líneas
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); 

Mi opinión es: no permita que Core Animation dibuje sombras usando las diversas properties de la capa . Simplemente dibuja una image prerendida a ambos lados, que de hecho es una sombra. Factorizar la altura variable de una celda en un estiramiento puede hacer el truco.

EDITAR: si el background es simple, una sombra prerregistrada se puede aplicar a ambos lados sin saber que está afectando el atractivo visual.

En caso de que no sea aplicable, la vista de tabla debe networkingucirse para que sea del tamaño sin sombra. Entonces, la sombra puede combinarse sin hacerlo por cada celda, sino simplemente "en la parte superior". Realmente no se desplaza. Esto solo funcionará si la sombra no tiene ninguna "textura", de lo contrario, uno notará que solo se aplica en la parte superior.