core animation 用于优化内容显示 以及 动画,动画包含了旋转,平移,放缩以及在此基础上已经封装好的 效果。优化内容比如说我们app里的一个图像加载在一个layer里,然后用layer去加在各个view上,这样子就不会在内存里产生重复的图像的副本。
1.1layer和view的区别。
CAlayer 绘制内容的层,它是对view所对应的lyaer的一个补充。只管理内容(如位图)的状态位移信息。layer不能代替view因为layer 不带交互的特性。它是渲染系统的内容模型。一个view至少对应一个layer,通常负载的应用view可以有多个layer。
view的drawRect: 为什么尽量不使用此方法,因为这个是用主线程的cpu去操作的,相当耗损性能。
动画后面的层树
1)model layer tree 就是代码所改变的那一层
2)presentation tree layer tree 当前屏幕显示的状态值,可读,但不可写
3 )render tree 私有渲染树 不归IOS程序员管。
1.2layer 管理内容的状态,动画的基本内容
1) frame,position,anchor point . position 是由bound和achorpoint决定的。
2 )transform 有已定义的transform也 可自定义其函数,本质上是形变矩阵
3) layer的presentationLayer属性可以访问动画进行中的属性。
4 )sublayerTransform 用于产生透视效果
1.3一些封好的layer的类
1.3.1在view中改变layer
+ (Class) layerClass { |
return [CAEAGLLayer class]; |
} |
Table 2-1 CALayer subclasses and their uses
Class | Usage |
Used to implement a Core Animation–based 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). | |
CAEAGLLayer/CAOpenGLLayer | 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 layer’s 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. |
2 layer内容提供
2.1 image
直接赋值contents属性。如果你用retina图片来设置,请手动把 contentsScale设成2.0.这个是必须的操作
2.2 delegate
- (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]; |
} |
} |
2.3 子类化一个layer
When subclassing, you can use either of the following techniques to draw your layer’s content:
- 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.
eg:
- (void)drawInContext:(CGContextRef)ctx
{
UIGraphicsPushContext(ctx);
[color setFill];
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:self.bounds];
[path fill];
UIGraphicsPopContext();
}
2.4layer的外观
contentsGravity 图片变大时,position-based gravity是决定了显示的部分(切分为9个部分),kCAGravityResize 表明要进行放缩
myLayer.backgroundColor = [NSColor greenColor].CGColor; |
myLayer.borderColor = [NSColor blackColor].CGColor; |
myLayer.borderWidth = 3.0; |
masksToBounds决定那个corner Radius是否有效。同样,maskToBounds值为YES会导致外部阴影被裁剪掉,如果需要开启maskToBounds又需要阴影,请使用两个layer。
3让layer动起来 Demo: ShowCase ->Path Demo
3.1 不管是CATransition还是CABacicAnimation,显式建立线性动画,它并不直接改变动画的值。改变值还是得用改变属性的方法而不是建立动画后自己以为它会自动跳到末尾值。
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 |
3.2 建立非线性动画。 Demo: ShowCase ->Path Demo
Listing 3-3 Creating a bounce keyframe animation
建立非线性动画意味着自己建立动画的值系列,它可以是一些值的数组,如果这些值的类型都是CGPoint,那么就可以指定path。在大多数情况下,使用NSValue去封装CGRect以及CATransform3D,使用NSNumber去封装CGFloat等,至于CGColorRef,则需将其转换成id类型。
// 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. |
theAnimation=[CAKeyframeAnimation animationWithKeyPath:@"position"]; |
theAnimation.path=thePath; |
theAnimation.duration=5.0; |
|
// Add the animation to the layer. |
[theLayer addAnimation:theAnimation forKey:@"position"]; |
3.3 Specifying the Timing of a Keyframe Animation
使用calculationMode来指定动画时间控制模式,
1) 使用kCAAnimationLinear or kCAAnimationCubic时,同时使用the keyTimes and timingFunctions properties.keyTimes是一个关于绑定时间-帧值的数组,然后timingFunctions控制了所有未指定的值,它允许你指定 ease-in or ease-out
3.4移除动画
1)使用removeAnimationForKey
2)removeAllAnimations
3.5使用Animation Group 做并行动画
// 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, nil]; |
colorAnim.values = colorValues; |
colorAnim.calculationMode = kCAAnimationPaced; |
|
// Animation group |
CAAnimationGroup* group = [CAAnimationGroup animation]; |
group.animations = [NSArray arrayWithObjects:colorAnim, widthAnim, nil]; |
group.duration = 5.0; |
|
[myLayer addAnimation:group forKey:@"BorderChanges"]; |
3.6动画结束后。。
2)使用 animationDidStart: andanimationDidStop:finished: delegate methods.
3.7关于autolayout和animation
关于view的constraints影响了 position 和 size。 所以如果发现有冲突,就在动画期间将 constraints先去掉,然后在动画结束后把constraints加回来
3.7关于在类中建立的动画 和 显式动画
[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"]; |
}]; |
4 关于层树
一旦一个view增加了复杂的动画,意味着这个view要管理自己的 layer的层级关系。同时,了解父layer的属性子layer的影响关系是非常重要的。
4.1 speed属性,是层树关系中的一个乘数因子,它会引起时间控制的速度的翻倍。这个参数不仅影响到layer自己还会叠加到子layer,因而会在子layer产生speed的倍数叠加。有不少属性都会影响到子类,如transform和opacity
Table 4-1 Methods for modifying the layer hierarchy
Behavior | Methods | Description |
Adding layers | Adds a new sublayer object to the current layer. The sublayer is added to the end of the layer’s list of sublayers. This causes the sublayer to appear on top of any siblings with the same value in their zPosition property. | |
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 sublayer’s position in the sublayers array. The actual visibility of the layers is determined primarily by the value in their zPositionproperty and secondarily by their position in the sublayersarray. | |
Removing layers | Removes the sublayer from its parent layer. | |
Exchanging layers | Exchanges one sublayer for another. If the sublayer you are inserting is already in another layer hierarchy, it is removed from that hierarchy first.
|
4.2手动管理层数
1)在一个layer的delegate中调整所有其子layer的布局,可以用layoutSublayersOfLayer:
2)在一个子类化的过程中,也可以重载- (void)layoutSublayers
4.3当要转换不同layer同一坐标
5关于Animation的技巧
5.1 CATranstion和a property-based animation的区别,CATransition同样继承于CAAction,但是不太可能在这个过程中改变laye属性进行动画,CATransition还是主要通过 perform reveal, push, move, or crossfade animations
以及subType进行就控制
5.2时间控制技巧
Listing 5-3 Getting a layer’s current local time
CFTimeInterval localLayerTime = [myLayer convertTime:CACurrentMediaTime() fromLayer:nil]; |
convertTime:fromLayer: and convertTime:toLayer:,利用这个可以进行显式动画衔接
使用beginTime 和 CACurrentMediaTime()可以通过
Pausing and Resuming Animations
Listing 5-4 暂停和恢复动画
-(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; |
} |
5.3景深
sublayerTransform 便利的矩阵,适用于所有子类
zPosition,只有在父layer设定了视口的位置之后,才会产生景深。设定视口是这样子设的
CATransform3D perspective = CATransform3DIdentity; |
perspective.m34 = -1.0/eyePosition; |
|
// Apply the transform to a parent layer. |
myParentLayer.sublayerTransform = perspective; |
5.4 CATransition 和 CABasimation
CATransition 跟 CABasicAnimation 的区别是 CABasicAnimation是 基于属性的动画,而CATransition是基于类型的,有type和subtype,当然,可以指定 progress的 开始和结束百分比。