IOS Core Animation
IOS Core Animation
Contents
Contents
Adjusting a Layers Visual Style and Appearance 35 Layers Have Their Own Background and Border 36 Layers Support a Corner Radius 37 Layers Support Built-In Shadows 38 Filters Add Visual Effects to OS X Views 39 The Layer Redraw Policy for OS X Views Affects Performance 40 Adding Custom Properties to a Layer 42 Printing the Contents of a Layer-Backed View 42
Contents
Animatable Properties 86
CALayer Animatable Properties 86 CIFilter Animatable Properties 89
Contents
Animatable Properties 86
Table B-1 Table B-2 Table B-3 Layer properties and their default animations 86 Default Implied Basic Animation 88 Default Implied Transition 88
Table C-2 Table C-3 Table C-4 Table C-5 Listing C-1
Transform field value key paths 92 CGPoint data structure fields 93 CGSize data structure fields 93 CGRect data structure fields 94 Example implementation of defaultValueForKey: 91
Core Animation is a graphics rendering and animation infrastructure available on both iOS and OS X that you use to animate the views and other visual elements of your app. With Core Animation, most of the work required to draw each frame of an animation is done for you. All you have to do is configure a few animation parameters (such as the start and end points) and tell Core Animation to start. Core Animation does the rest, handing most of the actual drawing work off to the onboard graphics hardware to accelerate the rendering. This automatic graphics acceleration results in high frame rates and smooth animations without burdening the CPU and slowing down your app. If you are writing iOS apps, you are using Core Animation whether you know it or not. And if you are writing OS X apps, you can take advantage of Core Animation with extremely little effort. Core Animation sits beneath AppKit and UIKit and is integrated tightly into the view workflows of Cocoa and Cocoa Touch. Of course, Core Animation also has interfaces that extend the capabilities exposed by your apps views and give you more fine-grained control over your apps animations.
At a Glance
You may never need to use Core Animation directly, but when you do you should understand the role that Core Animation plays as part of your apps infrastructure.
10
Prerequisites
You should already understand the view architecture of your target platform and be familiar with how to create view-based animations. If not, you should read one of the following documents:
For iOS apps, you should understand the view architecture described in View Programming Guide for iOS . For OS X apps, you should understand the view architecture described in View Programming Guide .
See Also
For examples of how to implement specific types of animations using Core Animation, see Core Animation Cookbook .
11
Core Animation provides a general purpose system for animating views and other visual elements of your app. Core Animation is not a replacement for your apps views. Instead, it is a technology that integrates with views to provide better performance and support for animating their content. It achieves this behavior by caching the contents of views into bitmaps that can be manipulated directly by the graphics hardware. In some cases, this caching behavior might require you to rethink how you present and manage your apps content, but most of the time you use Core Animation without ever knowing it is there. In addition to caching view content, Core Animation also defines a way to specify arbitrary visual content, integrate that content with your views, and animate it along with everything else. You use Core Animation to animate changes to your apps views and visual objects. Most changes relate to modifying the properties of your visual objects. For example, you might use Core Animation to animate changes to a views position, size, or opacity. When you make such a change, Core Animation animates between the current value of the property and the new value you specify. You would typically not use Core Animation to replace the content of a view 60 times a second, such as in a cartoon. Instead, you use Core Animation to move a views content around the screen, fade that content in or out, apply arbitrary graphics transformations to the view, or change the views other visual attributes.
12
Core Animation Basics Layers Provide the Basis for Drawing and Animations
a change triggers an animation, Core Animation passes the layers bitmap and state information to the graphics hardware, which does the work of rendering the bitmap using the new information, as shown in Figure 1-1. Manipulating the bitmap in hardware yields much faster animations than could be done in software.
Figure 1-1 How Core Animation draws content
App Window Core Animation Layer Object
App Window
Because it manipulates a static bitmap, layer-based drawing differs significantly from more traditional view-based drawing techniques. With view-based drawing, changes to the view itself often result in a call to the views drawRect: method to redraw content using the new parameters. But drawing in this way is expensive because it is done using the CPU on the main thread. Core Animation avoids this expense by whenever possible by manipulating the cached bitmap in hardware to achieve the same or similar effects. Although Core Animation uses cached content as much as possible, your app must still provide the initial content and update it from time to time. There are several ways for your app to provide a layer object with content, which are described in detail in Providing a Layers Contents (page 30).
Layer-Based Animations
The data and state information of a layer object is decoupled from the visual presentation of that layers content onscreen. This decoupling gives Core Animation a way to interpose itself and animate the change from the old state values to new state values. For example, changing a layers position property causes Core Animation
13
to move the layer from its current position to the newly specified position. Similar changes to other properties cause appropriate animations. Figure 1-2 illustrates a few of the types of animations you can perform on layers. For a list of layer properties that trigger animations, see Animatable Properties (page 86).
Figure 1-2 Examples of animations you can perform on layers
During the course of an animation, Core Animation does all of the frame-by-frame drawing for you in hardware. All you have to do is specify the start and end points of the animation and let Core Animation do the rest. You can also specify custom timing information and animation parameters as needed; however, Core Animation provides suitable default values if you do not. For more information about how to initiate animations and configure animation parameters, see Animating Layer Content (page 43).
14
use to position the layer and its content. Layers also have other properties that views do not have, such as an anchor point, which defines the point around which manipulations occur. The way you specify some aspects of layer geometry also differs from how you specify that information for a view.
One thing to note in Figure 1-3 (page 15) is that the position property is located in the middle of the layer. That property is one of several whose definition changes based on the value in the layers anchorPoint property. The anchor point represents the point from which certain coordinates originate and is described in more detail in Anchor Points Affect Geometric Manipulations (page 17).
15
The anchor point is one of several properties that you specify using the unit coordinate system. Core Animation uses unit coordinates to represent properties whose values might change when the layers size changes. You can think of the unit coordinates as specifying a percentage of the total possible value. Every coordinate in the unit coordinate space has a range of 0.0 to 1.0. For example, along the x-axis, the left edge is at the coordinate 0.0 and the right edge is at the coordinate 1.0. Along the y-axis, the orientation of unit coordinate values changes depending on the platform, as shown in Figure 1-4.
Figure 1-4 The default unit coordinate systems for iOS and OS X
iOS OS X
Note: Until OS X 10.8, the geometryFlipped property was a way to change the default orientation of a layers y-axis when needed. Use of this property was sometimes necessary to correct the orientation of a layer when flip transforms were in involved. For example, if a parent view used a flip transform, the contents of its child views (and their corresponding layers) would often be inverted. In such cases, setting the geometryFlipped property of the child layers to YES was an easy way to correct the problem. In OS X 10.8 and later, AppKit manages this property for you and you should not modify it. For iOS apps, it is recommended that you do not use the geometryFlipped property at all.
All coordinate values, whether they are points or unit coordinates are specified as floating-point numbers. The use of floating-point numbers allows you to specify precise locations that might fall between normal coordinate values. The use of floating-point values is convenient, especially during printing or when drawing to a Retina display where one point might be represented by multiple pixels. Floating-point values allow you to ignore the underlying device resolution and just specify values at the precision you need.
16
17
Figure 1-5 demonstrates how changing the anchor point from its default value to a different value affects the position property of a layer. Even though the layer has not moved within its parents bounds, moving the anchor point from the center of the layer to the layers bounds origin changes the value in the position property.
Figure 1-5 How the anchor point affects the layers position property
iOS OS X
18
Figure 1-6 shows how changing the anchor point affects transforms applied to the layer. When you apply a rotation transform to the layer, the rotations occur around the anchor point. Because the anchor point is set to the middle of the layer by default, this normally creates the kind of rotation behavior that you would expect. However, if you change the anchor point, the results of the rotation are different.
Figure 1-6 How the anchor point affects layer transformations
iOS OS X
19
use that property to scale or rotate the layer or change its position temporarily. The sublayerTransform property defines additional transformations that apply only to the sublayers and is used most commonly to add a perspective visual effect to the contents of a scene. Transforms work by multiplying coordinate values through a matrix of numbers to get new coordinates that represent the transformed versions of the original points. Because Core Animation values can be specified in three dimensions, each coordinate point has four values that must be multiplied through a four-by-four matrix, as shown in Figure 1-7. In Core Animation, the transform in the figure is represented by the CATransform3D type. Fortunately, you do not have to modify the fields of this structure directly to perform standard transformations. Core Animation provides a comprehensive set of functions for creating scale, translation, and rotation matrices and for doing matrix comparisons. In addition to manipulating transforms using functions, Core Animation extends key-value coding support to allow you to modify a transform using key paths. For a list of key paths you can modify, see CATransform3D Key Paths (page 92).
Figure 1-7 Converting a coordinate using matrix math
Figure 1-8 shows the matrix configurations for some of the more common transformations you can make. Multiplying any coordinate by the identity transform returns the exact same coordinate. For other transformations, how the coordinate is modified depends entirely on which matrix components you change.
20
Core Animation Basics Layer Trees Reflect Different Aspects of the Animation State
For example, to translate along the x-axis only, you would supply a nonzero value for the tx component of the translation matrix and leave the ty and tz values to 0. For rotations, you would provide the appropriate sine and cosine values of the target rotation angle.
Figure 1-8 Matrix configurations for common transformations
For information about the functions you use to create and manipulate transforms, see Core Animation Function Reference .
Objects in the model layer tree (or simply layer tree) are the ones your app interacts with the most. The objects in this tree are the model objects that store the target values for any animations. Whenever you change the property of a layer, you use one of these objects. Objects in the presentation tree contain the in-flight values for any running animations. Whereas the layer tree objects contain the target values for an animation, the objects in the presentation tree reflect the current values as they appear onscreen. You should never modify the objects in this tree. Instead, you use these objects to read current animation values, perhaps to create a new animation starting at those values. Objects in the render tree perform the actual animations and are private to Core Animation.
21
Core Animation Basics Layer Trees Reflect Different Aspects of the Animation State
Each set of layer objects is organized into a hierarchical structure like the views in your app. In fact, for an app that enables layers for all of its views, the initial structure of each tree matches the structure of the view hierarchy exactly. However, an app can add additional layer objectsthat is, layers not associated with a viewinto the layer hierarchy as needed. You might do this in situations to optimize your apps performance for content that does not require all the overhead of a view. Figure 1-9 shows the breakdown of layers found in a simple iOS app. The window in the example contains a content view, which itself contains a button view and two standalone layer objects. Each view has a corresponding layer object that forms part of the layer hierarchy.
Figure 1-9 Layers associated with a window
22
Core Animation Basics Layer Trees Reflect Different Aspects of the Animation State
For every object in the layer tree, there is a matching object in the presentation and render trees, as shown in Figure 1-10. As was previously mentioned, apps primarily work with objects in the layer tree but may at times access objects in the presentation tree. Specifically, accessing the presentationLayer property of an object in the layer tree returns the corresponding object in the presentation tree. You might want to access that object to read the current value of a property that is in the middle of an animation.
Figure 1-10 The layer trees for a window
Application Layer Tree Presentation Tree
Display
23
Important: You should access objects in the presentation tree only while an animation is in flight. While an animation is in progress, the presentation tree contains the layer values as they appear onscreen at that instant. This behavior differs from the layer tree, which always reflects the last value set by your code and is equivalent to the final state of the animation.
In addition to the layers associated with your views, you can also create layer objects that do not have a corresponding view. You can embed these standalone layer objects inside of any other layer object in your app, including those that are associated with a view. You typically use standalone layer objects as part of a specific optimization path. For example, if you wanted to use the same image in multiple places, you could
24
load the image once and associate it with multiple standalone layer objects and add those objects to the layer tree. Each layer then refers to the source image rather than trying to create its own copy of that image in memory. For information about how to enable layer support for your apps views, see Enabling Core Animation Support in Your App (page 26). For information on how to create a layer object hierarchy, and for tips on when you might do so, see Building a Layer Hierarchy (page 53).
25
Layer objects are at the heart of everything you do with Core Animation. Layers manage your apps visual content and provide options for modifying the style and visual appearance of that content. Although iOS apps have layer support enabled automatically, developers of OS X apps must enable it explicitly before they can take advantage of the performance benefits. Once enabled, you need to understand how to configure and manipulate your apps layers to get the effects you want.
Link against the QuartzCore framework. (iOS apps must link against this framework only if they use Core Animation interfaces explicitly.) Enable layer support for one or more of your NSView objects by doing one of the following:
In your nib files, use the View Effects inspector to enable layer support for your views. The inspector displays checkboxes for the selected view and its subviews. It is recommended that you enable layer support in the content view of your window whenever possible. For views you create programmatically, call the views setWantsLayer: method and pass a value of YES to indicate that the view should use layers.
Enabling layer support in one of the preceding ways creates a layer-backed view. With a layer-backed view, the system takes responsibility for creating the underlying layer object and for keeping that layer updated. In OS X, it is also possible to create a layer-hosting view, whereby your app actually creates and manages the underlying layer object. (You cannot create layer-hosting views in iOS.) For more information on how to create a layer-hosting view, see Layer Hosting Lets You Change the Layer Object in OS X (page 28).
26
Setting Up Layer Objects Changing the Layer Object Associated with a View
Your view draws content using OpenGL ES, in which case you would use a CAEAGLLayer object. There is a specialized layer class that offers better performance. You want to take advantage of some specialized Core Animation layer classes, such as particle emitters or replicators.
Changing the layer class of a view is very straightforward; an example is shown in Listing 2-1. All you have to do is override the layerClass method and return the class object you want to use instead. Prior to display, the view calls the layerClass method and uses the returned class to create a new layer object for itself. Once created, a views layer object cannot be changed.
Listing 2-1 Specifying the layer class of an iOS view
For a list of layer classes and how you use them, see Different Layer Classes Provide Specialized Behaviors (page 29).
27
Setting Up Layer Objects Changing the Layer Object Associated with a View
// Create myView...
If you choose to host layers yourself, you must set the contentsScale property yourself and provide high-resolution content at appropriate times. For more information about high-resolution content and scale factors, see Working with High-Resolution Images (page 35).
28
Setting Up Layer Objects Changing the Layer Object Associated with a View
Used to implement a Core Animationbased particle emitter system. The emitter layer object controls the generation of the particles and their origin. Used to draw a color gradient that fills the shape of the layer (within the bounds of any rounded corners). Used to set up the backing store and context needed to draw using OpenGL ES (iOS) or OpenGL (OS X). Used when you want to make copies of one or more sublayers automatically. The replicator makes the copies for you and uses the properties you specify to alter the appearance or attributes of the copies. Used to manage a large scrollable area composed of multiple sublayers. Used to draw a cubic Bezier spline. Shape layers are advantageous for drawing path-based shapes because they always result in a crisp path, as opposed to a path you draw into a layers backing store, which would not look as good when scaled. However, the crisp results do involve rendering the shape on the main thread and caching the results. Used to render a plain or attributed string of text. Used to manage a large image that can be divided into smaller tiles and rendered individually with support for zooming in and out of the content. Used to render a true 3D layer hierarchy, rather than the flattened layer hierarchy implemented by other layer classes. Used to render a Quartz Composer composition. (OS X only)
CAGradientLayer
CAEAGLLayer/CAOpenGLLayer
CAReplicatorLayer
CAScrollLayer
CAShapeLayer
CATextLayer CATiledLayer
CATransformLayer
QCCompositionLayer
29
Assign an image object directly to the layer objects contents property. (This technique is best for layer content that never, or rarely, changes.) Assign a delegate object to the layer and let the delegate draw the layers content. (This technique is best for layer content that might change periodically and can be provided by an external object, such as a view.) Define a layer subclass and override one of its drawing methods to provide the layer contents yourself. (This technique is appropriate if you have to create a custom layer subclass anyway or if you want to change the fundamental drawing behavior of the layer.)
The only time you need to worry about providing content for a layer is when you create the layer object yourself. If your app contains nothing but layer-backed views, you do not have to worry about using any of the preceding techniques to provide layer content. Layer-backed views automatically automatically provide the contents for their associated layers in the most efficient way possible.
30
If your delegate implements the displayLayer: method, that implementation is responsible for creating a bitmap and assigning it to the layers contents property. If your delegate implements the drawLayer:inContext: method, Core Animation creates a bitmap, creates a graphics context to draw into that bitmap, and then calls your delegate method to fill the bitmap. All your delegate method has to do is draw into the provided graphics context.
The delegate object must implement either the displayLayer: or drawLayer:inContext: method. If the delegate implements both the displayLayer: and drawLayer:inContext: method, the layer calls only the displayLayer: method. Overriding the displayLayer: method is most appropriate for situations when your app prefers to load or create the bitmaps it wants to display. Listing 2-3 shows a sample implementation of the displayLayer: delegate method. In this example, the delegate uses a helper object to load and display the image it needs. The delegate method selects which image to display based on its own internal state, which in the example is a custom property called displayYesImage.
Listing 2-3 Setting the layer contents directly
- (void)displayLayer:(CALayer *)theLayer { // Check the value of some state property if (self.displayYesImage) { // Display the Yes image theLayer.contents = [someHelperObject loadStateYesImage]; } else { // Display the No image theLayer.contents = [someHelperObject loadStateNoImage]; } }
If you do not have prerendered images or a helper object to create bitmaps for you, your delegate can draw the content dynamically using the drawLayer:inContext: method. Listing 2-4 shows a sample implementation of the drawLayer:inContext: method. In this example, the delegate draws a simple curved path using a fixed width and the current rendering color.
Listing 2-4 Drawing the contents of a layer
31
For layer-backed views with custom content, you should continue to override the views methods to do your drawing. A layer-backed view automatically makes itself the delegate of its layer and implements the needed delegate methods, and you should not change that configuration. Instead, you should implement your views drawRect: method to draw your content. In OS X v10.8 and later, an alternative to drawing is to provide a bitmap by overriding the wantsUpdateLayer and updateLayer methods of your view. Overriding wantsUpdateLayer and returning YES causes the NSView class to follow an alternate rendering path. Instead of calling drawRect:, the view calls your updateLayer method, the implementation of which must assign a bitmap directly to the layers contents property. This is the one scenario where AppKit expects you to set the contents of a views layer object directly.
32
When subclassing, you can use either of the following techniques to draw your layers content:
Override the layers display method and use it to set the contents property of the layer directly. Override the layers drawInContext: method and use it to draw into the provided graphics context.
Which method you override depends on how much control you need over the drawing process. The display method is the main entry point for updating the layers contents, so overriding that method puts you in complete control of the process. Overriding the display method also means that you are responsible for creating the CGImageRef to be assigned to the contents property. If you just want to draw content (or have your layer manage the drawing operation), you can override the drawInContext: method instead and let the layer create the backing store for you.
The position-based gravity constants allow you to pin your image to a particular edge or corner of the layers bounds rectangle without scaling the image. The scaling-based gravity constants allow you to stretch the image using one of several options, some of which preserve the aspect ratio and some of which do not.
Figure 2-1 shows the how the position-based gravity settings affect your images. With the exception of the kCAGravityCenter constant, each constant pins the image to a particular edge or corner of the layers bounds rectangle. The kCAGravityCenter constant centers the image in the layer. None of these constants
33
cause the image to be scaled in any way, so the image is always rendered at its original size. If the image is bigger than the layers bounds, this may result in portions of the image being clipped, and if the image is smaller, the portions of the layer that are not covered by the image reveal the layers background color, if set.
Figure 2-1 Position-based gravity constants for layers
Figure 2-2 shows how the scaling-based gravity constants affect your images. All of these constants scale the image if it does not fit exactly within the bounds rectangle of the layer. The difference between the modes is how they deal with the images original aspect ratio. Some modes preserve it and others do not. By default, a layers contentsGravity property is set to the kCAGravityResize constant, which is the only mode that does not preserve the image aspect ratio.
Figure 2-2 Scaling-based gravity constants for layers
34
35
Listing 2-5 shows the code needed to set the background color and border for a layer. All of these properties are animatable.
Listing 2-5 Setting the background color and border of a layer
36
Note: You can use any type of color for the background of a layer, including colors that have transparency or use a pattern image. When using pattern images, though, be aware that Core Graphics handles the rendering of the pattern image and does so using its standard coordinate system, which is different than the default coordinate system in iOS. As such, images rendered on iOS appear upside down by default unless you flip the coordinates.
If you set your layers background color to an opaque color, consider setting the layers opaque property to YES. Doing so can improve performance when compositing the layer onscreen and eliminates the need for the layers backing store to manage an alpha channel. You must not mark a layer as opaque if it also has a nonzero corner radius, though.
To apply a corner radius to your layer, specify a value for the cornerRadius property of the layer. The radius value you specify is measured in points and applied to all four corners of the layer prior to display.
37
When adding shadows to a layer, the shadow is part of the layers content but actually extends outside the layers bounds rectangle. As a result, if you enable the masksToBounds property for the layer, the shadow effect is clipped around the edges. If your layer contains any transparent content, this can cause an odd effect where the portion of the shadow directly under your layer is still visible but the part extending beyond your layer is not. If you want a shadow but also want to use bounds masking, you use two layers instead of one. Apply the mask to the layer containing your content and then embed that layer inside a second layer of the exact same size that has the shadow effect enabled. For examples of how shadows are applied to layers, see Shadow Properties (page 82).
38
For a given layer, you can apply filters to both the foreground and background content of the layer. The foreground content consists of everything that the layer itself contains, including the image in its contents property, its background color, its border, and the content of its sublayers. The background content is the content that is directly under the layer but not actually part of the layer itself. The background content of most layers is the content of its immediate superlayer, which may be wholly or partially obscured by the layer. For example, you might apply a blur filter to the background content when you want the user to focus on the layers foreground content. You specify filters by adding CIFilter objects to the following properties of your layer:
The filters property contains an array of filters that affect the layers foreground content only. The backgroundFilters property contains an array of filters that affect the layers background content only. The compositingFilter property defines how the layers foreground and background content are composited together.
To add a filter to a layer, you must first locate and create the CIFilter object and then configure it before adding it to your layer. The CIFilter class includes several class methods for locating the available Core Image filters, such as the filterWithName: method. Creating the filter is only the first step, though. Many filters have parameters that define how the filter modifies an image. For example, a box blur filter has an input radius parameter that affects the amount of blur that is applied. You should always provide values for these parameters as part of the filter configuration process. However, one common parameter that you do not need to specify is the input image, which is provided by the layer itself. When adding filters to layers, it is best to configure the filter parameters prior to adding the filter to the layer. The main reason for doing so is that once added to the layer, you cannot modify the CIFilter object itself. However, you can use the layers setValue:forKeyPath: method to change filter values after the fact.
39
Setting Up Layer Objects The Layer Redraw Policy for OS X Views Affects Performance
Listing 2-6 shows how to create and apply a pinch distortion filter to a layer object. This filter pinches the source pixels of the layer inward, distorting those pixels closest to the specified center point the most. Notice in the example that you do not need to specify the input image for the filter because the layers image is used automatically.
Listing 2-6 Applying a filter to a layer
CIFilter* aFilter = [CIFilter filterWithName:@"CIPinchDistortion"]; [aFilter setValue:[NSNumber numberWithFloat:500.0] forKey:@"inputRadius"]; [aFilter setValue:[NSNumber numberWithFloat:1.25] forKey:@"inputScale"]; [aFilter setValue:[CIVector vectorWithX:250.0 Y:150.0] forKey:@"inputCenter"];
For information about the available Core Image filters, see Core Image Filter Reference .
40
Setting Up Layer Objects The Layer Redraw Policy for OS X Views Affects Performance
NSViewLayerContentsRedrawOnSetNeedsDisplay
This is the recommended policy. With this policy, view geometry changes do not automatically cause the view to update its layers contents. Instead, the layers existing contents are stretched and manipulated to facilitate the geometry changes. To force the view to redraw itself and update the layers contents, you must explicitly call the views setNeedsDisplay: method. This policy most closely represents the standard behavior for Core Animation layers. However, it is not the default policy and must be set explicitly.
NSViewLayerContentsRedrawDuringViewResize
This is the default redraw policy. This policy maintains maximum compatibility with traditional AppKit drawing by recaching the layers contents whenever the views geometry changes. This behavior results in the views drawRect: method being called multiple times on your apps main thread during the resize operation. With this policy, AppKit draws the layer at its final size prior to any resize operations and caches that bitmap. The resize operation uses the cached bitmap as the starting image, scaling it to fit the old bounds rectangle. It then animates the bitmap to its final size. This behavior can cause the views contents to appear stretched or distorted at the beginning of an animation and is better in situations where the initial appearance is not important or not noticeable. With this policy, AppKit does not update the layer at all, even when you call the setNeedsDisplay: method. This policy is most appropriate for views whose contents never change and where the size of the view changes infrequently if at all. For example, you might use this for views that display fixed-size content or background elements.
NSViewLayerContentsRedrawBeforeViewResize
NSViewLayerContentsRedrawNever
View redraw policies alleviate the need to use standalone sublayers to improve drawing performance. Prior to the introduction of view redraw policies, there were some layer-backed views that drew more frequently than was needed and thereby caused performance issues. The solution to these performance issues was to use sublayers to present those portions of the views content that did not require regular redrawing. With the introduction of redraw policies in OS X v10.6, it is now recommended that you set a layer-backed views redraw policy to an appropriate value, rather than creating explicit sublayer hierarchies.
41
42
The infrastructure provided by Core Animation makes it easy to create sophisticated animations of your apps layers, and by extension to any views that own those layers. Examples include changing the size of a layers frame rectangle, changing its position onscreen, applying a rotation transform, or changing its opacity. With Core Animation, initiating an animation is often as simple as just changing the property but you can also create animations and set the animation parameters explicitly. For information about creating more advanced animations, see Advanced Animation Tricks (page 63).
theLayer.opacity = 0.0;
43
To make the same change explicitly using an animation object, create a CABasicAnimation object and use that object to configure the animation parameters. You can set the start and end values for the animation, change the duration, or change any other animation parameters before adding the animation to a layer. Listing 3-2 shows how to fade out a layer using an animation object. When creating the object, you specify the key path for the property you want to animate and then set your animation parameters. To execute the animation, you use the addAnimation:forKey: method to add it to the layers you want to animate.
Listing 3-2 Animating a change explicitly
CABasicAnimation* fadeAnim = [CABasicAnimation animationWithKeyPath:@"opacity"]; fadeAnim.fromValue = [NSNumber numberWithFloat:1.0]; fadeAnim.toValue = [NSNumber numberWithFloat:0.0]; fadeAnim.duration = 1.0; [theLayer addAnimation:fadeAnim forKey:@"opacity"];
// Change the actual data value in the layer to the final value. theLayer.opacity = 0.0;
Tip: When creating an explicit animation, it is recommended that you always assign a value to the fromValue property of the animation object. If you do not specify a value for this property, Core animation uses the layers current value as the starting value. If you already updated the property to its final value, that might not yield the results you want.
Unlike an implicit animation, which updates the layer objects data value, an explicit animation does not modify the data in the layer tree. Explicit animations only produce the animations. At the end of the animation, Core Animation removes the animation object from the layer and redraws the layer using its current data values. If you want the changes from an explicit animation to be permanent, you must also update the layers property as shown in the preceding example. Implicit and explicit animations normally begin executing after the current run loop cycle ends, and the current thread must have a run loop in order for animations to be executed. If you change multiple properties, or if you add multiple animation objects to a layer, all of those property changes are animated at the same time. For example, you can fade a layer while moving it offscreen by configuring both animations at the same time. However, you can also configure animation objects to start at a particular time. For more information about modifying animation timing, see Customizing the Timing of an Animation (page 65).
44
Listing 3-3 shows the code used to implement the animation in Figure 3-1. The path object in this example is used to define the position of the layer for each frame of the animation.
Listing 3-3 Creating a bounce keyframe animation
// create a CGPath that implements two arcs (a bounce) CGMutablePathRef thePath = CGPathCreateMutable(); CGPathMoveToPoint(thePath,NULL,74.0,74.0); CGPathAddCurveToPoint(thePath,NULL,74.0,500.0, 320.0,500.0, 320.0,74.0); CGPathAddCurveToPoint(thePath,NULL,320.0,500.0, 566.0,500.0, 566.0,74.0);
CAKeyframeAnimation * theAnimation;
// Create the animation object, specifying the position property as the key path.
45
For properties that take a CGRect (such as the bounds and frame properties), wrap each rectangle in an NSValue object. For the layers transform property, wrap each CATransform3D matrix in an NSValue object. Animating this property causes the keyframe animation to apply each transform matrix to the layer in turn. For the borderColor property, cast each CGColorRef data type to the type id before adding it to the array. For properties that take a CGFloat value, wrap each value in an NSNumber object before adding it to the array. When animating the layers contents property, specify an array of CGImageRef data types.
For properties that take a CGPoint data type, you can create an array of points (wrapped in NSValue objects) or you can use a CGPathRef object to specify the path to follow. When you specify an array of points, the keyframe animation object draws a straight line between each successive point and follows that path. When you specify a CGPathRef object, the animation starts at the beginning point of the path and follows its outline, including along any curved surfaces. You can use either an open or closed path.
46
The calculationMode property defines the algorithm to use in calculating the animation timing. The value of this property affects how the other timing-related properties are used.
Linear and cubic animationsthat is, animations where the calculationMode property is set to kCAAnimationLinear or kCAAnimationCubicuse the provided timing information to generate the animation. These modes give you the maximum control over the animation timing. Paced animationsthat is, animations where the calculationMode property is set to kCAAnimationPaced or kCAAnimationCubicPaceddo not rely on the external timing values provided by the keyTimes or timingFunctions properties. Instead, timing values are calculated implicitly to provide the animation with a constant velocity. Discrete animationsthat is, animations where the calculationMode property is set to kCAAnimationDiscretecause the animated property to jump from one keyframe value to the next without any interpolation. This calculation mode uses the values in the keyTimes property but ignores the timingFunctions property
The keyTimes property specifies time markers at which to apply each keyframe value. This property is used only if the calculation mode is set to kCAAnimationLinear, kCAAnimationDiscrete, or kCAAnimationCubic. It is not used for paced animations. The timingFunctions property specifies the timing curves to use for each keyframe segment. (This property replaces the inherited timingFunction property.)
If you want to handle the animation timing yourself, use the kCAAnimationLinear or kCAAnimationCubic mode and the keyTimes and timingFunctions properties. The keyTimes defines the points in time at which to apply each keyframe value. The timing for all intermediate values is controlled by the timing functions, which allow you to apply ease-in or ease-out curves to each segment. If you do not specify any timing functions, the timing is linear.
To remove a single animation object from the layer, call the layers removeAnimationForKey: method to remove your animation object. This method uses the key that was passed to the addAnimation:forKey: method to identify the animation. The key you specify must not be nil. To remove all animation objects from the layer, call the layers removeAllAnimations method. This method removes all ongoing animations immediately and redraws the layer using its current state information.
47
When you remove an animation from a layer, Core Animation responds by redrawing the layer using its current values. Because the current values are usually the end values of the animation, this can cause the appearance of the layer to jump suddenly. If you want the layers appearance to remain where it was on the last frame of the animation, you can use the objects in the presentation tree to retrieve those final values and set them on the objects in the layer tree. For information about pausing an animation temporarily, see Listing 5-4 (page 66).
// Animation 1 CAKeyframeAnimation* widthAnim = [CAKeyframeAnimation animationWithKeyPath:@"borderWidth"]; NSArray* widthValues = [NSArray arrayWithObjects:@1.0, @10.0, @5.0, @30.0, @0.5, @15.0, @2.0, @50.0, @0.0, nil]; widthAnim.values = widthValues; widthAnim.calculationMode = kCAAnimationPaced;
// Animation 2 CAKeyframeAnimation* colorAnim = [CAKeyframeAnimation animationWithKeyPath:@"borderColor"]; NSArray* colorValues = [NSArray arrayWithObjects:(id)[UIColor greenColor].CGColor, (id)[UIColor redColor].CGColor, (id)[UIColor blueColor].CGColor, colorAnim.values = colorValues; colorAnim.calculationMode = kCAAnimationPaced; nil];
48
// Animation group CAAnimationGroup* group = [CAAnimationGroup animation]; group.animations = [NSArray arrayWithObjects:colorAnim, widthAnim, nil]; group.duration = 5.0;
A more advanced way to group animations together is to use a transaction object. Transactions provide more flexibility by allowing you to create nested sets of animations and assign different animation parameters for each. For information about how to use transaction objects, see Explicit Transactions Let You Change Animation Parameters (page 67).
Add a completion block to the current transaction using the setCompletionBlock: method. When all of the animations in the transaction finish, the transaction executes your completion block. Assign a delegate to your CAAnimation object and implement the animationDidStart: and animationDidStop:finished: delegate methods.
If you want to chain two animations together so that one starts when the other finishes, do not use animation notifications. Instead, use the beginTime property of your animation objects to start each one at the desired time. To chain two animations together, set the start time of the second animation to the end time of the first animation. For more information about animation and timing values, see Customizing the Timing of an Animation (page 65).
49
// Change the position explicitly. CABasicAnimation* theAnim = [CABasicAnimation animationWithKeyPath:@"position"]; theAnim.fromValue = [NSValue valueWithCGPoint:myView.layer.position]; theAnim.toValue = [NSValue valueWithCGPoint:myNewPosition]; theAnim.duration = 3.0; [myView.layer addAnimation:theAnim forKey:@"AnimateFrame"]; }];
50
anchorPoint bounds compositingFilter filters frame geometryFlipped hidden position shadowColor shadowOffset shadowOpacity shadowRadius transform
Important: The preceding restrictions do not apply to layer-hosting views. If you created the layer object and associated it with a view manually, you are responsible for modifying the properties of that layer and keeping the corresponding view object in sync. AppKit disables implicit animations for its layer-backed views by default. The views animator proxy object reenables implicit animations automatically for you. If you want to animate layer properties directly, you can also programmatically reenable implicit animations by changing the allowsImplicitAnimation property of the current NSAnimationContext object to YES. Again, you should do this only for animatable properties that are not in the preceding list.
51
52
Most of the time, the best way to use layers in your app is to use them in conjunction with a view object. However, there are times when you might need to enhance your view hierarchy by adding additional layer objects to it. You might use use layers when doing so offers better performance or lets you implement a feature that would be difficult to do with views alone. In those situations, you need to know how to manage the layer hierarchies you create. Important: In OS X v10.8 and later, it is recommended that you minimize your use of layer hierarchies and just use layer-backed views. The layer redraw policies introduced in that version of OS X let you customize the behavior of your layer-backed views and still get the kind of performance you might have gotten previously using standalone layers.
Adding layers
Adds a new sublayer object to the current layer. The sublayer is added to the end of the layers list of sublayers. This causes the sublayer to appear on top of any siblings with the same value in their zPosition property.
53
Behavior
Description
Inserting layers
Inserts the sublayer into the sublayer hierarchy at the specified index or at a position relative to another sublayer. When inserting above or below another sublayer, you are only specifying the sublayers position in the sublayers array. The actual visibility of the layers is determined partially primarily by the value in their zPosition property and secondarily by their position in the sublayers array. Removes the sublayer from its parent layer.
removeFromSuperlayer
replaceSublayer: with:
Exchanges one sublayer for another. If the sublayer you are inserting is already in another layer hierarchy, it is removed from that hierarchy first.
You use the preceding methods when working with layer objects you created yourself. You would not use these methods to arrange layers that belong to layer-backed views. However, a layer-backed view can act as the parent for standalone layers you create yourself.
54
Important: Always use integral numbers for the width and height of your layer.
Create one or more CAConstraint objects. Use those objects to define the constraint parameters. Add your constraint objects to the layer whose attributes they modify. Retrieve the shared CAConstraintLayoutManager object and assign to the immediate superlayer.
Figure 4-1 shows the attributes that you can use to define a constraint and the aspect of the layer that they impact. You can use constraints to change the position the layer based on the position of its edges of midpoints relative to another layer. You can also use them to change the size of the layer. The changes you make can be
55
proportional to the superlayer or relative to another layer. You can even add a scaling factor or constant to the resulting change. This extra flexibility makes it possible to control a layers size and position very precisely using a simple set of rules.
Figure 4-1 Constraint layout manager attributes
Each constraint object encapsulates one geometry relationship between two layers along the same axis. A maximum of two constraint objects may be assigned to each axis and it is those two constraints that determine which attribute is changeable. For example, if you specify constraints for the left and right edge of the layer, the size of the layer changes. If you specify constraints for the left edge and width of the layer, the location of the layers right edge changes. If you specify a single constraint for one of the layers edges, Core Animation creates an implicit constraint that keeps the size of the layer fixed in the given dimension. When creating constraints, you must always specify three pieces of information:
The aspect of the layer that you want to constrain The layer to use as a reference The aspect of the reference layer to use in the comparison
Listing 4-1 shows a simple constraint that pins the vertical midpoint of a layer to the vertical midpoint of its superlayer. When referring to the superlayer, use the string superlayer. This string is a special name reserved for referring to the superlayer. Using it eliminates needing to have a pointer to the layer or know the layers name. It also allows you to change the superlayer and have the constraint apply automatically to the new parent. (When creating constraints relative to sibling layers, you must identify the sibling layer using its name property.)
56
Listing 4-1
To apply constraints at runtime, you must attach the shared CAConstraintLayoutManager object to the immediate superlayer. Each layer is responsible for managing the layout of its sublayers. Assigning the layout manager to the parent tells Core Animation to apply the constraints defined by its children. The layout manager object applies the constraints automatically. After assigning it to the parent layer, you do not have to tell it to update the layout. To see how constraints work in a more specific scenario, consider Figure 4-2. In this example, the design requires that the width and height of layerA remain unchanged and that layerA remain centered inside its superlayer. In addition, the width of layerB must match that of layerA, the top edge of layerB must remain 10 points below the bottom edge of layerA, and the bottom edge of layerB must remain 10 points above the bottom edge of the superlayer. Listing 4-2 (page 57) shows the code that you would use to create the sublayers and constraints for this example.
Figure 4-2 Example constraints based layout
Listing 4-2
// Create and set a constraint layout manager for the parent layer. theLayer.layoutManager=[CAConstraintLayoutManager layoutManager];
57
// Create the first sublayer. CALayer *layerA = [CALayer layer]; layerA.name = @"layerA"; layerA.bounds = CGRectMake(0.0,0.0,100.0,25.0); layerA.borderWidth = 2.0;
// Keep layerA centered by pinning its midpoint to its parent's midpoint. [layerA addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMidY relativeTo:@"superlayer" attribute:kCAConstraintMidY]]; [layerA addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMidX relativeTo:@"superlayer" attribute:kCAConstraintMidX]]; [theLayer addSublayer:layerA];
// Create the second sublayer CALayer *layerB = [CALayer layer]; layerB.name = @"layerB"; layerB.borderWidth = 2.0;
// Make the width of layerB match the width of layerA. [layerB addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintWidth relativeTo:@"layerA" attribute:kCAConstraintWidth]];
// Make the horizontal midpoint of layerB match that of layerA [layerB addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMidX relativeTo:@"layerA" attribute:kCAConstraintMidX]];
// Position the top edge of layerB 10 points from the bottom edge of layerA. [layerB addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMaxY relativeTo:@"layerA" attribute:kCAConstraintMinY
58
offset:-10.0]];
// Position the bottom edge of layerB 10 points // from the bottom edge of the parent layer.
[theLayer addSublayer:layerB];
One interesting thing to note about Listing 4-2 (page 57) is that the code never sets the size of layerB explicitly. Because of the defined constraints, the width and height of layerB are set automatically every time the layout is updated. Therefore, setting the size using the bounds rectangle is unnecessary. Warning: When creating constraints, do not create circular references among your constraints. Circular constraints make it impossible to calculate the needed layout information. When such circular references are encountered, the layout behavior is undefined.
59
60
The shape of a layers clipping mask includes the layers corner radius, if one is specified. Figure 4-3 shows a layer that demonstrates how the masksToBounds property affects a layer with rounded corners. When the property is set to NO, sublayers are displayed in their entirety, even if they extend beyond the bounds of their parent layer. Changing the property to YES causes their content to be clipped.
Figure 4-3 Clipping sublayers to the parents bounds
In addition to converting point and rectangle values, you can also convert time values between layers using the convertTime:fromLayer: and convertTime:toLayer: methods. Each layer defines its own local time space and uses that time space to synchronize the beginning and ending of animations with the rest of
61
the system. These time spaces are synchronized by default; however, if you change the animation speed for one set of layers, the time space for those layers changes accordingly. You can use the time conversion methods to to account for any such factors and ensure that the timing of both layers is synchronized.
62
There are many ways to configure your property-based or keyframe animations to do more for you. Apps that need to perform multiple animations together or sequentially can use more advanced behaviors to synchronize the timing of those animations or chain them together. You can also use other types of animation objects to create visual transitions and other interesting animated effects.
63
// Add the transition animation to both layers [myView1.layer addAnimation:transition forKey:@"transition"]; [myView2.layer addAnimation:transition forKey:@"transition"];
// Finally, change the visibility of the layers. myView1.hidden = YES; myView2.hidden = NO;
When two layers are involved in the same transition, you can use the same transition object for both. Using the same transition object also simplifies the code you have to write. However, you can use different transition objects and would definitely need to do so if the transition parameters for each layer are different. Listing 5-2 shows how to use a Core Image filter to implement a transition effect on OS X. After configuring the filter with the parameters you want, assign it to the filter property of the transition object. After that, the process for applying the animation is the same as for other types of animation objects.
Listing 5-2 Using a Core Image filter to animate a transition on OS X
// Create the Core Image filter, setting several key parameters. CIFilter* aFilter = [CIFilter filterWithName:@"CIBarsSwipeTransition"]; [aFilter setValue:[NSNumber numberWithFloat:3.14] forKey:@"inputAngle"]; [aFilter setValue:[NSNumber numberWithFloat:30.0] forKey:@"inputWidth"]; [aFilter setValue:[NSNumber numberWithFloat:10.0] forKey:@"inputBarOffset"];
// Create the transition object CATransition* transition = [CATransition animation]; transition.startProgress = 0; transition.endProgress = 1.0; transition.filter = aFilter; transition.duration = 1.0;
64
Note: When using Core Image filters in an animation, the trickiest part is configuring the filter. For example, with the bar swipe transition, specifying an input angle that is too high or too low might make it seem as if no transition is happening. If you are not seeing the animation you expected, try adjusting your filter parameters to different values to see if that changes the results.
65
Once you have a time value in the layers local time, you can use that value to update the timing-related properties of an animation object or layer. With these timing properties, you can achieve some interesting animation behaviors, including:
Use the beginTime property to set the start time of an animation. Normally, animations begin during the next update cycle. You can use the beginTime parameter to delay the animation start time by several seconds. The way to chain two animations together is to set the begin time of one animation to match the end time of the other animation. If you delay the start of an animation, you might also want to set the fillMode property to kCAFillModeBackwards. This fill mode causes the layer to display the animations start value, even if the layer object in the layer tree contains a different value. Without this fill mode, you would see a jump to the final value before the animation starts executing. Other fill modes are available too.
The autoreverses property causes an animation to execute for the specified duration and then return to the starting value of the animation. You can combine this property with the repeatCount property to animate back and forth between the start and end values. Setting the repeat count to a whole number (such as 1.0) for an autoreversing animation causes the animation to stop on its starting value. Adding an extra half step (such as a repeat count of 1.5) causes the animation to stop on its end value. Use the timeOffset property with group animations to start some animations at a later time than others.
-(void)pauseLayer:(CALayer*)layer { CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil]; layer.speed = 0.0; layer.timeOffset = pausedTime; }
66
Advanced Animation Tricks Explicit Transactions Let You Change Animation Parameters
layer.speed = 1.0; layer.timeOffset = 0.0; layer.beginTime = 0.0; CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime; layer.beginTime = timeSincePause; }
One of the main reasons to use transactions is that within the confines of an explicit transaction, you can change the duration, timing function, and other parameters. You can also assign a completion block to the entire transaction so that your app can be notified when the group of animations finishes. Changing animation parameters requires modifying the appropriate key in the transaction dictionary using the setValue:forKey: method. For example, to change the default duration to 10 seconds, you would change the kCATransactionAnimationDuration key, as shown in Listing 5-6.
Listing 5-6 Changing the default duration of animations
[CATransaction begin];
67
Advanced Animation Tricks Explicit Transactions Let You Change Animation Parameters
You can nest transactions in situations where you want to provide different default values for different sets of animations. To nest one transaction inside of another, just call the begin class method again. Each begin call must be matched by a corresponding call to the commit method. Only after you commit the changes for the outermost transaction does Core Animation begin the associated animations. Listing 5-7 shows an example of one transaction nested inside another. In this example, the inner transaction changes the same animation parameter as the outer transaction but uses a different value.
Listing 5-7 Nesting explicit transactions
// Change the animation duration to two seconds [CATransaction setValue:[NSNumber numberWithFloat:2.0f] forKey:kCATransactionAnimationDuration]; // Move the layer to a new position theLayer.position = CGPointMake(0.0,0.0);
[CATransaction begin]; // Inner transaction // Change the animation duration to five seconds [CATransaction setValue:[NSNumber numberWithFloat:5.0f] forKey:kCATransactionAnimationDuration];
68
With the parent layer configured, you can change the zPosition property of any child layers and observe how their size changes based on their relative distance from the eye position.
69
Core Animation implements its implicit animation behaviors for layers using action objects. An action object is an object that conforms to the CAAction protocol and defines some relevant behavior to perform on a layer. All CAAnimation objects implement the protocol, and it is these objects that are usually assigned to be executed whenever a layer property changes. Animating properties is one type of action but you can define actions with almost any behavior you want. To do that, though, you have to define your action objects and associate them with your apps layer objects.
The value of one of the layers properties changed. This can be any of the layers properties and not just the animatable ones. (You can also associate actions with custom properties you add to your layers.) The key that identifies this action is the name of the property. The layer became visible or was added to a layer hierarchy. The key that identifies this action is kCAOnOrderIn. The layer was removed from a layer hierarchy. The key that identifies this action is kCAOnOrderOut. The layer is about to be involved in a transition animation. The key that identifies this action is kCATransition.
70
Changing a Layers Default Behavior Action Objects Must Be Installed On a Layer to Have an Effect
If the layer has a delegate and that delegate implements the actionForLayer:forKey: method, the layer calls that method. The delegate must do one of the following:
Return the action object for the given key. Return nil if it does not handle the action, in which case the search continues. Return the NSNull object, in which case the search ends immediately.
2. 3.
The layer looks for the given key in the layers actions dictionary. The layer looks in the style dictionary for an actions dictionary that contains the key. (In other word, the style dictionary contains an actions key whose value is also a dictionary. The layer looks for the given key in this second dictionary.) The layer calls its defaultActionForKey: class method. The layer performs the implicit action (if any) defined by Core Animation.
4. 5.
If you provide an action object at any of the appropriate search points, the layer stops its search and executes the returned action object. When it finds an action object, the layer calls that objects runActionForKey:object:arguments: method to perform the action. If the action you define for a given key is already an instance of the CAAnimation class, you can use the default implementation of that method to perform the animation. If you are defining your own custom object that conforms to the CAAction protocol, you must use your objects implementation of that method to take whatever actions are appropriate. Where you install your action objects depends on how you intend to modify the layer.
For actions that you might apply only in specific circumstances, or for layers that already use a delegate object, provide a delegate and implement its actionForLayer:forKey: method. For layer objects that do not normally use a delegate, add the action to the layers actions dictionary. For actions related to custom properties that you define on the layer object, include the action in the layers style dictionary. For actions that are fundamental to the behavior of the layer, subclass the layer and override the defaultActionForKey: method.
71
Changing a Layers Default Behavior Disable Actions Temporarily Using the CATransaction Class
Listing 6-1 shows an implementation of the delegate method used to provide action objects. In this case, the delegate looks for changes to the layers contents property and swaps the new contents into place using a transition animation.
Listing 6-1 Providing an action using a layer delegate object
if ([theKey isEqualToString:@"contents"]) {
theAnimation = [[CATransition alloc] init]; theAnimation.duration = 1.0; theAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]; theAnimation.type = kCATransitionPush; theAnimation.subtype = kCATransitionFromRight; } return theAnimation; }
72
Changing a Layers Default Behavior Disable Actions Temporarily Using the CATransaction Class
[CATransaction commit];
For more information about using transaction objects to manage animation behavior, see Explicit Transactions Let You Change Animation Parameters (page 67).
73
Core Animation is a great way to improve the frame rates for app-based animations but its use is not a guarantee of improved performance. Especially in OS X, you must still make choices about the most effective way to use Core Animation behaviors. And as with all performance-related issues, you should use Instruments to measure and track the performance of your app over time so that you can ensure that performance is improving and not regressing.
74
75
76
During the rendering process, Core Animation takes different attributes of the layer and renders them in a specific order. This order determines the final appearance of the layer. This chapter illustrates the rendered results achieved by setting different layer style properties. Note: The layer style properties available on Mac OS X and iOS differ and are noted throughout this chapter.
Geometry Properties
A layers geometry properties specify how it is displayed relative to its parent layer. The geometry also specifies the radius used to round the layer corners and a transform that is applied to the layer and its sublayers. Figure A-1 shows the bounding rectangle of the example layer.
Figure A-1 Layer geometry
bounds position frame (computed from the bounds and position and is not animatable) anchorPoint
77
iOS Note: The cornerRadius property is supported only in iOS 3.0 and later.
Background Properties
The first thing Core Animation renders is the layers background. You can specify a color for the background. In OS X, you can also specify a Core Image filter that you want to apply to the background content. Figure A-2 shows two versions of a sample layer. The layer on the left has its backgroundColor property set while the layer on the right has no background color but does have a border some content and a pinch distortion filter assigned to its backgroundFilters property.
Figure A-2 Layer with background color
The background filter is applied to the content that lies behind the layer, which primarily consists of the parent layers content. You might use a background filter to make the foreground layer content stand out; for example, by applying a blur filter. The following CALayer properties affect the display of a layers background:
78
Platform Note: In iOS, the backgroundFilters property is exposed in the CALayer class but the filters you assign to this property are ignored.
Layer Content
If the layer has any content, that content is rendered on top of the background color. You can provide layer content by setting a bitmap directly, by using a delegate to specify the content, or by subclassing the layer and drawing the content directly. And you can many different drawing technologies (including Quartz, OpenGL, and Quartz Composer) to provide that content. Figure A-3 shows a sample layer whose contents are a bitmap that was set directly. The bitmap content consists of a largely transparent space with the Automator icon in the lower right corner.
Figure A-3 Layer displaying a bitmap image
Layers with a corner radius do not automatically clip their contents; however, setting the layers masksToBounds property to YES does cause the layer to clip to its corner radius. The following CALayer properties affect the display of a layers content:
79
Sublayers Content
Any layer may contain one or more child layers, known as sublayers. Sublayers are rendered recursively and positioned relative to the parent layer's bounds rectangle. In addition, Core Animation applies the parent layers sublayerTransform to each sublayer relative to the parent layers anchor point. You can use the sublayer transform to apply perspective and other effects to all of the layers equally. Figure A-4 shows a sample layer with two sublayers. The version on the left includes a background color while the version on the right does not.
Figure A-4 Layer displaying the sublayers content
Setting the masksToBounds property of a layer to YES causes any sublayers to be clipped to the bounds of the layer. The following CALayer properties affect the display of a layers sublayers:
80
Border Attributes
A layer can display an optional border using a specified color and width. The border follows the bounds rectangle of the layer and takes into account any corner radius values. Figure A-5 shows a sample layer after applying a border. Notice that content and sublayers that are outside the layers bounds are rendered underneath the border.
Figure A-5 Layer displaying the border attributes content
borderColor borderWidth
81
Platform Note: The borderColor and borderWidth properties are supported only in iOS 3.0 and later.
Filters Property
In OS X, you may apply one or more filters to the layers content and use a custom compositing filter to specify how the layers contents blend with the content of its underlying layer. Figure A-6 shows a sample layer with the Core Image posterize filter applied.
Figure A-6 Layer displaying the filters properties
filters compositingFilter
Platform Note: In iOS, layers ignore any filters you assign to them.
Shadow Properties
Layers can display shadow effects and configure their shape, opacity, color, offset, and blur radius. If you do not specify a custom shadow shape, the shadow is based on the portions of the layer that are not fully transparent. Figure A-7 shows several different versions of the same sample layer with a red shadow applied.
82
The left and middle versions include a background color so the shadow appears only around the border of the layer. However, the version on the right does not include a background color. In this case, the shadow is applied to the layers content, border, and sublayers.
Figure A-7 Layer displaying the shadow properties
83
Platform Note: The shadowColor, shadowOffset, shadowOpacity, and shadowRadius properties are supported in iOS 3.2 and later. The shadowPath property is supported in iOS 3.2 and later and in OS X v10.7 and later.
Opacity Property
The opacity property of a layer determines how much background content shows through the layer. Figure A-8 shows a sample layer whose opacity is set to 0.5. This allows portions of the background image to show through.
Figure A-8 Layer including the opacity property
opacity
Mask Properties
You can use a mask to obscure all or part of a layers contents. The mask is itself a layer object whose alpha channel is used to determine what is blocked and what is transmitted. Opaque portions of the mask layers contents allow the underlying layer content to show through while transparent portions partially or fully obscure the underlying content. Figure A-9 shows a sample layer composited with a mask layer and two
84
different backgrounds. In the left version, the layers opacity is set to 1.0. In the right version, the layers opacity is set to 0.5, which increases the amount of background content that is transmitted through the masked portion of the layer.
Figure A-9 Layer composited with the mask property
mask
Platform Note: The mask property is supported in iOS 3.0 and later.
85
Animatable Properties
Many of the properties in CALayer and CIFilter can be animated. This appendix lists those properties, along with the animation used by default.
Uses the default implied CABasicAnimation object, described in Table B-2 (page 88). Uses the default implied CABasicAnimation object, described in Table B-2 (page 88). Uses the default implied CATransition object, described in Table B-3 (page 88). Sub-properties of the filters are animated using the default implied CABasicAnimation object, described in Table B-2 (page 88). Uses the default implied CABasicAnimation object, described in Table B-2 (page 88). Uses the default implied CABasicAnimation object, described in Table B-2 (page 88). Uses the default implied CABasicAnimation object, described in Table B-2 (page 88). Uses the default implied CATransition object, described in Table B-3 (page 88). Sub-properties of the filters are animated using the default implied CABasicAnimation object, described in Table B-2 (page 88). Uses the default implied CABasicAnimation object, described in Table B-2 (page 88).
backgroundColor
backgroundFilters
borderColor
borderWidth
bounds
compositingFilter
contents
86
Property contentsRect
Default animation
Uses the default implied CABasicAnimation object, described in Table B-2 (page 88). Uses the default implied CABasicAnimation object, described in Table B-2 (page 88). There is no default implied animation. Uses the default implied CABasicAnimation object, described in Table B-2 (page 88). Sub-properties of the filters are animated using the default implied CABasicAnimation object, described in Table B-2 (page 88). This property is not animatable. You can achieve the same results by animating the bounds and position properties. Uses the default implied CABasicAnimation object, described in Table B-2 (page 88). Uses the default implied CABasicAnimation object, described in Table B-2 (page 88). Uses the default implied CABasicAnimation object, described in Table B-2 (page 88). Uses the default implied CABasicAnimation object, described in Table B-2 (page 88). Uses the default implied CABasicAnimation object, described in Table B-2 (page 88). Uses the default implied CABasicAnimation object, described in Table B-2 (page 88). Uses the default implied CABasicAnimation object, described in Table B-2 (page 88). Uses the default implied CABasicAnimation object, described in Table B-2 (page 88). Uses the default implied CABasicAnimation object, described in Table B-2 (page 88). Uses the default implied CABasicAnimation object, described in Table B-2 (page 88).
cornerRadius
doubleSided filters
frame
hidden
mask
masksToBounds
opacity
position
shadowColor
shadowOffset
shadowOpacity
shadowPath
shadowRadius
87
Property sublayers
Default animation
Uses the default implied CABasicAnimation object, described in Table B-2 (page 88). Uses the default implied CABasicAnimation object, described in Table B-2 (page 88). Uses the default implied CABasicAnimation object, described in Table B-2 (page 88). Uses the default implied CABasicAnimation object, described in Table B-2 (page 88).
sublayerTransform
transform
zPosition
Table B-2 lists the animation attributes for the default property-based animations.
Table B-2 Description Default Implied Basic Animation Value CABasicAnimation
0.25 seconds, or the duration of the current transaction Set to the property name of the layer.
Table B-3 lists the animation object configuration for default transition-based animations.
Table B-3 Description Default Implied Transition Value CATransition
88
name enabled
For more information about these additions, see CIFilter Core Animation Additions .
89
Core Animation extends the NSKeyValueCoding protocol as it pertains to the CAAnimation and CALayer classes. This extension adds default values for some keys, expands wrapping conventions, and adds key path support for CGPoint, CGRect, CGSize, and CATransform3D types.
You can also retrieve the value for arbitrary keys like you would retrieve the value for other key paths. For example, to retrieve the value of the someKey path set previously, you would use the following code:
someKeyValue=[theLayer valueForKey:@"someKey"];
OS X Note: The CAAnimation and CALayer classes, which automatically archive any additional keys that you set up for instances of those classes, support the NSCoding protocol.
90
To provide a default value for a key, create a subclass of the desired class and override its defaultValueForKey: method. Your implementation of this method should examine the key parameter and return the appropriate default value. Listing C-1 shows a sample implementation of the defaultValueForKey: method for a layer object that provides a default value for the masksToBounds property.
Listing C-1 Example implementation of defaultValueForKey:
Wrapping Conventions
When the data for a key consists of a scalar value or C data structure, you must wrap that type in an object before assigning it to the layer. Similarly, when accessing that type, you must retrieve an object and then unwrap the appropriate values using the extensions to the appropriate class. Table C-1 lists the C types commonly used and the Objective-C class you use to wrap them.
Table C-1 C type CGPoint CGSize CGRect CATransform3D CGAffineTransform Wrapper classes for C types Wrapping class NSValue NSValue NSValue NSValue NSAffineTransform (OS X only)
91
Set to an NSNumber object whose value is the rotation, in radians, in the x axis. Set to an NSNumber object whose value is the rotation, in radians, in the y axis. Set to an NSNumber object whose value is the rotation, in radians, in the z axis. Set to an NSNumber object whose value is the rotation, in radians, in the z axis. This field is identical to setting the rotation.z field. Set to an NSNumber object whose value is the scale factor for the x axis. Set to an NSNumber object whose value is the scale factor for the y axis. Set to an NSNumber object whose value is the scale factor for the z axis. Set to an NSNumber object whose value is the average of all three scale factors. Set to an NSNumber object whose value is the translation factor along the x axis. Set to an NSNumber object whose value is the translation factor along the y axis. Set to an NSNumber object whose value is the translation factor along the z axis. Set to an NSValue object containing an NSSize or CGSize data type. That data type indicates the amount to translate in the x and y axis.
translation
92
The following example shows how you can modify a layer using the setValue:forKeyPath: method. The example sets the translation factor for the x axis to 10 points, causing the layer to shift by that amount along the indicated axis.
[myLayer setValue:[NSNumber numberWithFloat:10.0] forKeyPath:@"transform.translation.x"];
Note: Setting values using key paths is not the same as setting them using Objective-C properties. You cannot use property notation to set transform values. You must use the setValue:forKeyPath: method with the preceding key path strings.
Structure Field x y
The width component of the size. The height component of the size.
93
The origin of the rectangle as a CGPoint. The x component of the rectangle origin. The y component of the rectangle origin. The size of the rectangle as a CGSize. The width component of the rectangle size. The height component of the rectangle size.
94
Date 2013-01-28
Notes Major revamp, reorganization, and expansion to cover modern Core Animation behavior in iOS and OS X. Incorporated the content of Animation Types and Timing Programming Guide into this document.
2010-09-24 2010-08-12
Updated the document to reflect Core Animation support in iOS 4.2. Corrected iOS origin information. Clarified that the coordinate system origin used in the examples are based on the OS X model. Corrected autoresizing masks table. Added missing constant to the contentGravity property resizing table in Providing Layer Content. Updated Core Animation Kiosk Style Menu tutorial project. Updated infinite value for repeatCount. Modified section headings. Corrected availability of cornerRadius on iOS v 3.0 and later. Introduces iOS SDK content to OS X content. Corrects frame animation capabilities. Corrected typos. Updated for iOS.
2010-05-25 2010-03-24
2008-09-09 2008-06-18
95
Notes Corrected typos. Corrected typos. Corrected typos. Corrected RadiansToDegrees() calculation. Corrected typos. Added information on the presentation tree. Added example application walkthough.
96
Apple Inc. 2013 Apple Inc. All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, mechanical, electronic, photocopying, recording, or otherwise, without prior written permission of Apple Inc., with the following exceptions: Any person is hereby authorized to store documentation on a single computer for personal use only and to print copies of documentation for personal use provided that the documentation contains Apples copyright notice. No licenses, express or implied, are granted with respect to any of the technology described in this document. Apple retains all intellectual property rights associated with the technology described in this document. This document is intended to assist application developers to develop applications only for Apple-labeled computers. Apple Inc. 1 Infinite Loop Cupertino, CA 95014 408-996-1010 Apple, the Apple logo, Cocoa, Cocoa Touch, Instruments, Mac, Mac OS, Objective-C, OS X, and Quartz are trademarks of Apple Inc., registered in the U.S. and other countries. Retina is a trademark of Apple Inc. OpenGL is a registered trademark of Silicon Graphics, Inc. Times is a registered trademark of Heidelberger Druckmaschinen AG, available from Linotype Library GmbH. iOS is a trademark or registered trademark of Cisco in the U.S. and other countries and is used under license.
Even though Apple has reviewed this document, APPLE MAKES NO WARRANTY OR REPRESENTATION, EITHER EXPRESS OR IMPLIED, WITH RESPECT TO THIS DOCUMENT, ITS QUALITY, ACCURACY, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. AS A RESULT, THIS DOCUMENT IS PROVIDED AS IS, AND YOU, THE READER, ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND ACCURACY. IN NO EVENT WILL APPLE BE LIABLE FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES RESULTING FROM ANY DEFECT OR INACCURACY IN THIS DOCUMENT, even if advised of the possibility of such damages. THE WARRANTY AND REMEDIES SET FORTH ABOVE ARE EXCLUSIVE AND IN LIEU OF ALL OTHERS, ORAL OR WRITTEN, EXPRESS OR IMPLIED. No Apple dealer, agent, or employee is authorized to make any modification, extension, or addition to this warranty. Some states do not allow the exclusion or limitation of implied warranties or liability for incidental or consequential damages, so the above limitation or exclusion may not apply to you. This warranty gives you specific legal rights, and you may also have other rights which vary from state to state.