Rendering views using CALayer, Part 1




Before you jump straight to the code…

Before you go any farther, I highly suggest you download the WWDC 2010 videos, and watch the sessions on Core Animation. There’s a lot of great information there and the presenters go to great lengths to show how flexible Core Animation is. The summary though is that CALayer objects can be stacked and nested just like layers in Photoshop, and actually form the foundation for how UIViews interact. The interesting thing about Core Animation is that when a parent layer is animated, moved, or in any other way interacted with, the sub-layers come along for the ride.

Most people focus on Core Animation as a way of, duh, animating their UI. While this is the really powerful capability that Core Animation exposes, don’t be confused by its name. Using its simpler capabilities can give you quite a lot, even without the animation capabilities. Think of it as going to Disney Land; yes there are plenty of amazing rides that cost millions of dollars and years of engineering to produce, but you can still have a fantastic time riding the Teacups. Core Animation provides some remarkable tools to do high-speed sophisticated path and keyframe animations, but layers, borders, shadows and gradient layers are still very effective tools.

Starting with your view

Typically when you’re creating your own custom view, you’ll start by subclassing UIView. This is what I’ll be doing here as well, but one of the things many people don’t realize is that with every instance of a UIView object, you get a CALayer for free. The layer property contains a default backing-store that your view will render itself to. At this point you can either draw directly to the layer using Core Graphics drawing operations, or you can create additional sub-layers for your view.

- (id)initWithCoder:(NSCoder *)aDecoder {
    if ((self = [super initWithCoder:aDecoder])) {
        [self setupLayers];
    return self;

- (void)setupLayers {
    self.layer.cornerRadius = 10.0;
    self.layer.borderColor = [UIColor redColor].CGColor;
    self.layer.borderWidth = 1.0f;
    self.layer.shadowOffset = CGSizeMake(0.0f, 2.0f);
    self.layer.shadowOpacity = 1.5f;
    self.layer.shadowColor = [UIColor blackColor].CGColor;
    self.layer.shadowRadius = 2.5f;
    self.layer.anchorPoint = CGPointMake(0.5f, 0.5f);

This makes your view look something like the screenshot you see here. You’ll notice that, since our layer is empty except for the border, the shadow extends into the view itself. So, lets give our layer some content to display. The easiest way is to simply assign an image to the content property, but I want to be a bit more creative than that.

Instead, I’ll create a gradient inside this view. Add the following code to the end of the setupLayers method:

CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.anchorPoint = CGPointMake(0.0f, 0.0f);
gradient.position = CGPointMake(0.0f, 0.0f);
gradient.bounds = self.layer.bounds;
gradient.cornerRadius = 10.0;
gradient.colors = [NSArray arrayWithObjects:
                   (id)[UIColor colorWithRed:0.82f
                   (id)[UIColor colorWithRed:0.52f
[self.layer addSublayer:gradient];

This gives you something along these lines instead. While this is starting out quite simply, you can see how simple interfaces can be drawn by using declarative routines as opposed to using regular images, or even procedural calls using Core Graphics.

As I create more and more sophisticated custom views using CALayer, I’ll add more to my blog on the subject. Before I go, I’ll show a screenshot of what I’ve managed to accomplish for my new buttons.

3 thoughts on “Rendering views using CALayer, Part 1”

  1. Pingback: Tweets that mention Rendering views using CALayer, Part 1 | iOS/Web Developer's Life in Beta --

    1. I don’t have the time to write the code for you, but it should be fairly straight-forward. If you use UIBezierPath to define the jagged-edge outline, use that to create a CAShapeLayer, and then use that on the “mask” property for the actual layer displaying your content, you should be fine.

      [code lang=”ObjC”]
      UIBezierPath *path = [UIBezierPath bezierPath];

      CAShapeLayer *maskLayer = [CAShapeLayer layer];
      maskLayer.path = path.CGPath;

      theView.layer.mask = maskLayer;
      theView.layer.shadowColor = [UIColor blackColor].CGColor;


Leave a Reply
