Core Animation Basics
Layers Provide the Basis for Drawing and Animations
Layer objects are 2D surfaces organized in a 3D space and are at the heart of everything you do with Core Animation. Like views, layers manage information about the geometry, content, and visual attributes of their surfaces. Unlike views, layers do not define their own appearance. A layer merely manages the state information surrounding a bitmap. The bitmap itself can be the result of a view drawing itself or a fixed image that you specify. For this reason, the main layers you use in your app are considered to be model objects because they primarily manage data. This notion is important to remember because it affects the behavior of animations.
- layer对象是组织在三维空间的2d层面
- 跟view一样,layer管理几何,内容和可视属性,view跟layer不一样的时候,layer管理围绕一个位图的状态信息。
- layer作为一个model是因为它管理的是data!
The Layer-Based Drawing Model
Most layers do not do any actual drawing in your app. Instead, a layer captures the content your app provides and caches it in a bitmap, which is sometimes referred to as the backing store. When you subsequently change a property of the layer, all you are doing is changing the state information associated with the layer object. When a change triggers an animation, Core Animation passes the layer’s bitmap and state information to the graphics hardware, which does the work of rendering the bitmap
- layer捕获app提供的content并用位图缓存。动画触发时,动画把layer状态信息和位图交给硬件,渲染位图。
Manipulating the bitmap in hardware yields much faster animations than could be done in software.
layer是控制静态位图,相对于view-base的绘制技术,view-base每次使用新的参数来调用drawrect来重新绘制,这是发生在cpu的
mainthread,而且耗性能,layer操作缓存的bitmap来用硬件渲染,也会达到同样效果。
Layer-Based Animations
The data and state information of a layer object is decoupled from the visual presentation of that layer’s content onscreen
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.
有两种坐标系统
- point-based coordinate systems
Point-based coordinates are used when specifying values that map directly to screen coordinates or must be specified relative to another layer, such as for the layer’s position property.
- unit coordinate systems
Unit coordinates are used when the value should not be tied to screen coordinates because it is relative to some other value. For example, the layer’s anchorPoint property specifies a point relative to the bounds of the layer itself, which can change.
上图中,position是在layer中点的点,他是其中一个根据anchorpoint的值而发生改变的值
Anchor Points Affect Geometric Manipulations
Layers Can Be Manipulated in Three Dimensions
The transform property of CALayer specifies the transforms that you want to apply both to the layer and its embedded sublayers.
transform是由原作标经过一个4纬矩阵变换后得到的坐标,Core Animation已经为我们提供了全面的包括creating scale, translation, and rotation matrices and for doing matrix comparisons
各种变换的矩阵实现
三种layer树
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.Objects in the
presentation tree
contain the in-flight values for any running animations.Objects in the
render tree
perform the actual animations and are private to Core Animation.
layer层级
一般的基本操作都在model layer tree上面,每个model layer都有相关联的presentation tree和render tree,presentation tree 一般用于动画展示,可以用 presentationLayer获取动画过程中的layer属性
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.
presentation tree获取的是动画即使的属性,而layer tree 反应的是动画的最终属性和状态
Layers do not handle events, draw content, participate in the responder chain,
Setting Up Layer Objects
Changing the Layer Object Associated with a View
Changing the Layer Class Used by UIView
改变UIView的layer,可以重写
+ (Class) layerClass {
return [CAMetalLayer class];
}
CALayer子类
Providing a Layer’s Contents
A layer’s content consists of a bitmap containing the visual data you want to display. You can provide the content for that bitmap in one of three ways:
- Assign an image object directly to the layer object’s 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 layer’s 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.)
Using an Image for the Layer’s Content
因为layer就是一个bitmap image的容器,可以直接赋值content添加图片,CGImageRef类型的,当用layer设置图片时,要注意contentsScale 这个值,在点坐标系中,一个点对应contentsScale个pixel,给uiview设置图片contentsScale是自动适应屏幕的,给layer设置图片则需要设置scale
Using a Delegate to Provide the Layer’s Content
代理方法
- displayLayer:
- drawLayer:inContext:,如果代理实现了displayLayer:就不会实现这个方法。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.
Providing Layer Content Through Subclassing
- override the layer’s display method and use it to set the contents property of the layer directly.
- Override the layer’s drawInContext: method and use it to draw into the provided graphics context.
Tweaking the Content You Provide
Working with High-Resolution Images
Changing the value of the contentsScale property is only necessary if you are assigning a bitmap to your layer directly.
Adjusting a Layer’s Visual Style and Appearance
Layers Have Their Own Background and Border
Layers Support a Corner Radius
Because it involves applying a transparency mask, the corner radius does not affect the image in the layer’s contents property unless the masksToBounds property is set to YES
Layers Support Built-In Shadows
The opacity value for layer shadows is set to 0 by default, which effectively hides the shadow. Changing the opacity to a nonzero value causes Core Animation to draw the shadow
当又要圆角又要shadow的时候,maskToBounds会把阴影切掉,可以使用两个layer来实现
Animating Layer Content
- implicit animations 隐式动画 改变layer的属性
- explicit animation 显式动画 使用CABaseAnimation等实现,不会改变layer最终的属性值,you must also update the layer’s 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.
Using a Keyframe Animation to Change Layer Properties
Specifying Keyframe Values
- For properties that take a CGRect (such as the bounds and frame properties), wrap each rectangle in an NSValue object.
- For the layer’s 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 layer’s contents property, specify an array of CGImageRef data types.
Specifying the Timing of a Keyframe Animation
The calculationMode property defines the algorithm to use in calculating the animation timing.
- Linear and cubic animations—that is, animations where the calculationMode property is set to kCAAnimationLinear or kCAAnimationCubic—use the provided timing information to generate the animation. These modes give you the
maximum control
over the animation timing. - Paced animations—that is, animations where the calculationMode property is set to kCAAnimationPaced or kCAAnimationCubicPaced—
do 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 animations—that is, animations where the calculationMode property is set to kCAAnimationDiscrete—
cause 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 butignores the timingFunctions
property
Stopping an Explicit Animation While It Is Running
- To remove a single animation object from the layer, call the layer’s
removeAnimationForKey:
method to remove your animation object. This method uses the key that was passed to theaddAnimation:forKey:
method to identify the animation. The key you specify must not be nil. - To remove all animation objects from the layer, call the layer’s
removeAllAnimations
method. This method removes all ongoing animations immediately and redraws the layer using its current state information.
隐式动画不可以停止
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 layer’s 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
如果立即移除动画,layer会根据之前的属性绘制layer,会造成画面突然跳动到动画开始的layer的现象,可以通过presentation树来获取停止前的属性值
Animating Multiple Changes Together
- CAAnimationGroup
- 动画事务,更强大
Detecting the End of an Animation
There are two different ways to be notified about the state of an animation:
- 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:
andanimationDidStop: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
如果一个动画的开始再另一个动画的结束,最好不要用上面的方法,可以根据动画开始和结束的时间
Rules for Modifying Layers in iOS
[UIView animateWithDuration:1.0 animations:^{
// Change the opacity implicitly.
myView.layer.opacity = 0.0;
// 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"];
}];
Both animations start at the same time but the opacity animation runs with the default timing while the position animation runs with the timing specified in its animation object.
Remember to Update View Constraints as Part of Your Animation
Building a Layer Hierarchy
Arranging Layers into a Layer Hierarchy
Adding, Inserting, and Removing Sublayers
When adding and inserting sublayers, you must set the size and position of the sublayer before it appears onscreen. You can modify the size and position of a sublayer after adding it to your layer hierarchy but should get in the habit of setting those values when you create the layer.
Positioning and Sizing Sublayers
You set the size of a sublayer using the bounds property and set its position within its superlayer using the position property. The origin of the bounds rectangle is almost always (0, 0) and the size is whatever size you want for the layer specified in points. The value in the position property is interpreted relative to the layer’s anchor point, which is located in the center of the layer by default. If you do not assign values to these properties, Core Animation sets the initial width and height of the layer to 0 and sets the position to (0, 0).
myLayer.bounds = CGRectMake(0, 0, 100, 100);
myLayer.position = CGPointMake(200, 200);
`Important: Always use integral numbers for the width and height of your layer.`
Sublayers and Clipping
Converting Coordinate Values Between Layers
坐标转换
- convertPoint:fromLayer:
- convertPoint:toLayer:
- convertRect:fromLayer:
- convertRect:toLayer:
时间转换。
In addition to converting point and rectangle values, you can also convert time values between layers using the
convertTime:fromLayer:
andconvertTime: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 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.
每个layer都有自己的时间空间,但不同layer的这些时间一般都是同步的,除非设置了layer的动画速度,此时可用时间转换函数
Advanced Animation Tricks
Customizing the Timing of an Animation
- CAAimation 遵循CAMediaTiming protocol
- The CALayer also adopts it so that you can configure some timing-related features for your implicit animations
Each layer has its own local time that it uses to manage animation timing. Normally, the local time of two different layers is close enough that you could specify the same time values for each and the user might not notice anything.
每个layer的时间都是相近的
layer’sspeed
property causes the duration of animations on that layer (and its sublayers) to change proportionally.
speed可以改变layer的时间系统To assist you in making sure time values are appropriate for a given layer, the CALayer class defines the
convertTime:romLayer:
andconvertTime:toLayer:
methods.
可以用上面这两个函数转换时间系统不同的layer的时间CACurrentMediaTime function is a convenience function that returns the computer’s current clock time, which the method takes and converts to the layer’s local time.
CACurrentMediaTime
可以获取标准的时间,可以用来计算当前layer的时间
CFTimeInterval localLayerTime = [myLayer convertTime:CACurrentMediaTime() fromLayer:nil];
- 两个动画衔接用begintime
Pausing and Resuming Animations
- adopt the CAMediaTiming protocol
-(void)pauseLayer:(CALayer*)layer {
CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
layer.speed = 0.0;
layer.timeOffset = pausedTime;
}
-(void)resumeLayer:(CALayer*)layer {
CFTimeInterval pausedTime = [layer timeOffset];
layer.speed = 1.0;
layer.timeOffset = 0.0;
layer.beginTime = 0.0;
CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
layer.beginTime = timeSincePause;
}
Explicit Transactions Let You Change Animation Parameters
Only after you commit the changes for the outermost transaction does Core Animation begin the associated animations
[CATransaction begin]; // Outer transaction
// 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];
// Change the zPosition and opacity
theLayer.zPosition=200.0;
theLayer.opacity=0.0;
[CATransaction commit]; // Inner transaction
[CATransaction commit]; // Outer transaction
Adding Perspective to Your Animations
position
Changing a Layer’s Default Behavior
Disable Actions Temporarily Using the CATransaction Class
[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue
forKey:kCATransactionDisableActions];
[aLayer removeFromSuperlayer];
[CATransaction commit];