views:

777

answers:

2

I'm using CALayers to draw to a UITableViewCell. I'm trying to figure out how layers are ordered with the content of the UITableViewCell. For instance:

  1. I add labels to the UITableViewCell in my cellForRow:atIndexPath method
  2. In the drawRect method of UITableViewCell I draw some content using the current context
  3. Also, in drawRect I add a few sublayers

So what would be the order of these elements. I know I have zPosition on the CALayers but I'm not sure if they are always on top of any subviews of the UITableViewCell. And I'm not sure where the content that is drawn in drawRect comes in the order. Any help or links to documentation would be great. I have read through the Core Animation Programming Guide and didn't see anywhere where this would be answered.

+1  A: 

CALayers maintain a hierarchy, just like views do. Sublayers render in front of their superlayer, all the up the hierarchy. The zPosition property should only be used to control the rendering of sibling layers by placing one above the other. Even then, it's preferred that you order the sibling layers within the sublayers property (the layers draw in the order they are within that array, with each successive layer drawn upon the one before it in the array).

It's pretty easy to see this hierarchy, because you are manually adding sublayers to a layer when you create them in your code, all the way back to the backing layer for your UITableViewCell (a subclass of the layer-backed UIView).

As an aside, you really should not be adding layers to your UITableViewCell within its -drawRect: method. That should only be used for drawing the content of the base layer of the UITableViewCell. Allocating and setting CALayers within this method may lead to significant slowdown while scrolling or redrawing. You should only need to set up these layers once at some point when the UITableViewCell is initialized, then simply update them as the cell is reused.

Brad Larson
I'm curious on where the proper place is to build my layer hierarchy? Is it acceptable for the UITableViewController to add sublayers to UITableViewCell.layer? The two layers I have is one that is the background of the cell which is drawn with a CGGradient, and the other is a layer that will appear above the UITableViewCell. From U62's answer, it seems that I should just draw the gradient on the cell. I did this before but changed it to a layer because I heard layers cache. The gradient on is semi-transparent to look like a gloss, but scrolling is jerky.
Brian
I forgot - I also tried drawing the gradient and storing as a CGImage to layer.contents. But when I run with Core Animation in Instruments, it shows the gradient is still blending colors. - Thanks for all your help.
Brian
@Brian: Layers do cache, but your views are layer-backed. If you're not redrawing the gradient for every time the table view cell is reused, your gradient won't be redrawn if you just draw it on your background view in Quartz. However, if you're looking for a high-performance implementation of gradients, you might want to check out Matt Gallagher's CAGradientLayer example: http://cocoawithlove.com/2009/08/adding-shadow-effects-to-uitableview.html
Brad Larson
@Brian: If you have multiple layers, they will be composited on the GPU any time things animate around the screen, which is why Apple recommends flattening your view or layer hierarchy to smooth out your scrolling. I believe they provide an example application to this end.
Brad Larson
+1  A: 
  1. Your UITableViewCell (or derived class) derives from UIView. It owns one CALayer which you can access via the layer property. This layer takes up the whole area of the view. The UILabels you add to your cell view will be children of your cell's UIView and their CALayer will be a child of the cell's CALayer. Child layers are drawn in front of their parents.
  2. When you draw anything in UIView's drawRect method, the CALayer the UIView owns will become backed by a bitmap. Your UILabels will obscure this bitmap partially or fully depending on how big they are.
  3. Any child CALayers you add to your cell's layer later will be siblings of the UILabel's layers and since you added them later they will be added under them by default (there are versions of the method that adds them which can control ordering though).

Note that drawing in a UITableViewCell and using child views at the same time isn't recommended for performance reasons. Having more than 4 child views/layers isn't recommended for the same reason.

U62
So then the order of visibility would be - from bottom to top:UITableViewCell background bitmap - UITableViewCell.layer - UILabel background bitmap - UILabel.layer ? If this is true, then UILabel.layer is a sublayer of UITableViewCell.layer?
Brian