< Previous PageNext Page > Hide TOC

Providing Layer Content

Contents:

Providing CALayer Content
Positioning Content Within a Layer


Providing CALayer Content

When using Cocoa views you must subclass NSView or UIView and implement drawRect: in order to display anything. However CALayer instances can often be used directly, without requiring you to create a subclass. Because CALayer is a key-value coding compliant container class, that is you can store arbitrary values in any instance, subclassing can often be avoided entirely.

You specify the content of a CALayer instance in one of the following ways:

Setting the Contents Property

A layer’s content image is specified by contents property to a CGImageRef. This can be done from another object when the layer is created (as shown in Table 3) or at any other time.

Listing 4  Setting a layer’s contents property

CALayer *theLayer;
 
// create the layer and set the bounds and position
theLayer=[CALayer layer];
theLayer.position=CGPointMake(50.0f,50.0f);
theLayer.bounds=CGRectMake(0.0f,0.0f,100.0f,100.0f);
 
// set the contents property to a CGImageRef
// specified by theImage (loaded elsewhere)
theLayer.contents=theImage;

Using a Delegate to Provide Content

You can draw content for your layer, or better encapsulate setting the layer’s content image by creating a delegate class that implements one of the following methods: displayLayer: or drawLayer:inContext:.

Implementing a delegate method to draw the content does not automatically cause the layer to draw using that implementation. Instead, you must explicitly tell a layer instance to re-cache the content, either by sending it a setNeedsDisplay or setNeedsDisplayInRect: message, or by setting its needsDisplayOnBoundsChange property to YES.

Delegates that implement the displayLayer: method can determine which image should be displayed for the specified layer, and then set that layer’s contents property accordingly. The example in implementation of displayLayer: in “Layer Coordinate System” sets the contents property of theLayer depending on the value of the state key. Subclassing is not required to store the state value, as the CALayer instance acts as a key-value coding container.

Listing 5  Example implementation of the delegate method displayLayer:

 
- (void)displayLayer:(CALayer *)theLayer
{
    // check the value of the layer's state key
    if ([[theLayer valueForKey:@"state"] boolValue])
    {
        // display the yes image
        theLayer.contents=[someHelperObject loadStateYesImage];
    }
    else {
        // display the no image
        theLayer.contents=[someHelperObject loadStateNoImage];
    }
}

If you must draw the layer’s content rather than loading it from an image, you implement the drawLayer:inContext: delegate method. The delegate is passed the layer for which content is required and a CGContextRef to draw the content in.

The example in implementation of drawLayer:inContext:: in “Specifying a Layer’s Geometry” draws a path in using the lineWidth key value returned by theLayer.

Listing 6  Example implementation of the delegate method drawLayer:inContext:

 
- (void)drawLayer:(CALayer *)theLayer
        inContext:(CGContextRef)theContext
{
    CGMutablePathRef thePath = CGPathCreateMutable();
 
    CGPathMoveToPoint(thePath,NULL,15.0f,15.f);
    CGPathAddCurveToPoint(thePath,
                          NULL,
                          15.f,250.0f,
                          295.0f,250.0f,
                          295.0f,15.0f);
 
    CGContextBeginPath(theContext);
    CGContextAddPath(theContext, thePath );
 
    CGContextSetLineWidth(theContext,
                          [[theLayer valueForKey:@"lineWidth"] floatValue]);
    CGContextStrokePath(theContext);
 
    // release the path
    CFRelease(thePath);
}

Providing CALayer Content by Subclassing

Although often unnecessary, you can subclass CALayer and override the drawing and display methods directly. This is typically done when your layer requires custom behavior that can’t be provided though delegation.

A subclass can override the CALayer display method and set the layer’s contents to the appropriate image. The example in “Transforming a Layer’s Geometry”provides the same functionality as the delegate implementation of displayLayer: in “Layer Coordinate System.” The difference is that the subclass defines state as instance property, rather than depending on the key-value coding container ability of CALayer.

Listing 7  Example override of the CALayer display method

 
- (void)display
{
    // check the value of the layer's state key
    if (self.state)
    {
        // display the yes image
        self.contents=[someHelperObject loadStateYesImage];
    }
    else {
        // display the no image
        self.contents=[someHelperObject loadStateNoImage];
    }
}

CALayer subclasses can draw the layer’s content into a graphics context by overriding drawInContext:. The example in “Modifying the Transform Data Structure” produces the same content image as the delegate implementation in “Specifying a Layer’s Geometry.” Again, the only difference in the implementation is that lineWidth and lineColor are now declared as instance properties of the subclass.

Listing 8  Example override of the CALayer drawInContext: method

 
- (void)drawInContext:(CGContextRef)theContext
{
    CGMutablePathRef thePath = CGPathCreateMutable();
 
    CGPathMoveToPoint(thePath,NULL,15.0f,15.f);
    CGPathAddCurveToPoint(thePath,
                          NULL,
                          15.f,250.0f,
                          295.0f,250.0f,
                          295.0f,15.0f);
 
    CGContextBeginPath(theContext);
    CGContextAddPath(theContext, thePath );
 
    CGContextSetLineWidth(theContext,
                          self.lineWidth);
    CGContextSetStrokeColorWithColor(theContext,
                                     self.lineColor);
    CGContextStrokePath(theContext);
    CFRelease(thePath);
}

Subclassing CALayer and implementing one of the drawing methods does not automatically cause drawing to occur. You must explicitly cause the instance to re-cache the content, either by sending it a setNeedsDisplay or setNeedsDisplayInRect: message, or by setting its needsDisplayOnBoundsChange property to YES.

Positioning Content Within a Layer

The CALayer property contentsGravity allows you to position and scale the layer’s contents image within the layer bounds. By default, the content image fills the layer’s bounds entirely, ignoring the natural aspect ratio of the image.

Using the contentsGravity positioning constants you can specify that the image is placed along any of the layer’s edges, in the layer’s corners, or centered within the layer’s bounds. “Specifying a Layer’s Geometry” lists the positioning constants and their corresponding positions.

Table 7  Positioning constants for a layer’s contentsGravity property

Position constant

Description

kCAGravityTopLeft

Positions the content image in the top left corner of the layer.

kCAGravityTop

Positions the content image horizontally centered along the top edge of the layer.

kCAGravityTopRight

Positions the content image in the top right corner of the layer.

kCAGravityLeft

Positions the content image vertically centered on the left edge of the layer.

kCAGravityCenter

Positions the content image at the center of the layer.

kCAGravityRight

Positions the content image vertically centered on the right edge of the layer.

kCAGravityBottomLeft

Positions the content image in the bottom left corner of the layer.

kCAGravityBottom

Positions the content image centered along the bottom edge of the layer.

kCAGravityBottomRight

Positions the content image in the top right corner of the layer.

“Layer Coordinate System” shows the supported content positions and their corresponding constants.


Figure 9  Position constants for a layer’s contentsGravity property

Position constants for a layer’s contentsGravity property

The content image can be scaled up, or down, by setting the contentsGravity property to one of the gravity constants listed in “Transform Functions”

Table 8  Scaling constants for a layer’s contentsGravity property

Scaling constant

Description

kCAGravityResize

Resize the content image to completely fill the layer bounds, potentially ignoring the natural aspect of the content. This is the default.

kCAGravityResizeAspect

Resize the content image to scale such that it is displayed as large as possible within the layer bounds, yet still retains its natural aspect.

“Transforming a Layer’s Geometry” illustrates how a square image is resized to fit within a rectangular layer bounds using the resizing modes.


Figure 10  Scaling constants for a layer’s contentsGravity property

Scaling constants for a layer’s contentsGravity property



< Previous PageNext Page > Hide TOC


© 2008 Apple Inc. All Rights Reserved. (Last updated: 2008-11-13)


Did this document help you?
Yes: Tell us what works for you.
It’s good, but: Report typos, inaccuracies, and so forth.
It wasn’t helpful: Tell us what would have helped.