《核心动画编程指南》学习笔记
动态的动画接口很难创建,但是核心动画通过提供如下接口使这些创建起来变得更加简单:
-
1简单易用的高性能混合编程模型。
-
1类似视图一样,你可以通过使用图层来创建复杂的接口。
-
1轻量级的数据结构,它可以同时显示并让上百个图层产生动画效果。
-
1一套简单的动画接口,可以让你的动画运行在独立的线程里面,并可以独立于主线程之外。
-
1一旦动画配置完成并启动,核心动画完全控制并独立完成相应的动画帧。
-
1提高应用性能。应用程序只当发生改变的时候才重绘内容。再小的应用程序也需要改变和提供布局服务层。核心动画还消除了在动画的帧速率上运行的应用程序代码。
-
1灵活的布局管理模型。包括允许图层相对同级图层的关系来设置相应属性的位置和大小。
核心动画类有以下分类:
1、提供显示内容的图层类。
2、动画和计时类。
3、布局和约束类。
4、事务类,在原子更新的时候组合图层类。
CAEAGLLayer提供了一个OpenGLES渲染环境。
图层的很多可视化属性是可以隐式动画的。通过简单的改变图层的可动画显示的属性,可以让图层现有属性从当前值动画渐变到新的属性值。
动画的属性也可以显式动画。要显式动画的属性,你需要创建核心动画动画类的一个实例,并指定所需的视觉效果。显式动画不会改变该属性的值,它只是用于动画显示。
所有核心动画的动画类都是从CAAnimation类继承而来。
CAAnimation实现了 CAMediaTiming协议,提供了动画的持续时间,速度,和重复计数。CAAnimation也实现了CAAction协议。该协议为图层触发一个动画动作提供了提供标准化响应。
动画类同时定义了一个使用贝塞尔曲线来描述动画改变的时间函数。例如,一个匀速时间函数(lineartiming function)在动画的整个生命周期里面一直保持速度不变,而渐缓时间函数(ease-outtiming function)则在动画接近其生命周期的时候减慢速度。
核心动画额外提供了一系列抽象的和细化的动画类,比如:
CATransition提供了一个图层变化的过渡效果,它能影响图层的整个内容。动画进行的时候淡入淡出(fade)、推(push)、显露(reveal)图层的内容。这些过渡效果可以扩展到你自己定制的 Core Image 滤镜。
CAAnimationGroup允许一系列动画效果组合在一起,并行显示动画。
CAPropertyAnimation是一个抽象的子类,它支持动画的显示图层的关键路径中指定的属性
CABasicAnimation简单的为图层的属性提供修改。
CAKeyframeAnimation支持关键帧动画,你可以指定的图层属性的关键路径动画,包括动画的每个阶段的价值,以及关键帧时间和计时功能的一系列值。在动画运行是,每个值被特定的插入值替代。
图层的动画属性的每一个修改必然是事务的一个部分。CATransaction 是核心动画里面负责协调多个动画原子更新显示操作。事务支持嵌套使用。
核心动画支持两种事务: 隐式事务 和 显式事务。
图层的所有几何属性,包括图层的矩阵变换,都可以隐式和显式动画。
图层拥有一个隐式的 frame,它是 position,bounds,anchorPoint和transform属性的一部分。设置新的frame将会相应的改变图层的position和bounds属性,但是frame本身并没有被保存
Mac OS X 的图层,它的坐标系原点基于左下角。在 iOS 上面,图层的坐标系原点位于左上角,原点向下和向右为正值。
图层的几何变换
图层一旦创建,你就可以通过矩阵变换来改变一个图层的几何形状。CATransform3D的数据结构定义一个同质的三维变换(4x4CGFloat值的矩阵),用于图层的 旋转 , 缩放 , 偏移 , 歪斜 和 应用的透视。
图层的两个属性指定了变换矩阵:transform 和sublayerTransform属性。
图层的transform属性指定的矩阵结合图层的anchorPoint属性作用于图层和图层的子图层上面。
你可以通过以下的任何一个方法改变 CATransform3D的数据结构:
1、使用CATransform3D函数
2、直接修改数据结构的成员
3、使用键-值编码改变键路径
CATransform3DIdentity是单位矩阵,该矩阵没有缩放、旋转、歪斜、透视。把该矩阵应用到图层上面,会把图层几何属性修改为默认值。
变换函数
使用变换函数可以在核心动画里面在操作矩阵。你可以使用这些函数(如下表)去创建一个矩阵一般后面用于改变图层或者它的子图层的transform和sublayerTransform属性。变换函数或者直接操或者返回一个CATransform3D的数据结构。这可以让你能够构建简单或复杂的转换,以便重复使用。
旋转的单位采用弧度(radians),而不是角度(degress)。以下两个函数,你可以在弧度和角度之间切换:
CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;};
你可以修改 CATransform3D的数据结构的元素为任何其他你想要的数据值。清单1 包含了CATransform3D数据结构的定义,结构的成员都在其相应的矩阵位置。
struct CATransform3D
{
CGFloat m11, m12, m13, m14;
CGFloat m21, m22, m23, m24;
CGFloat m31, m32, m33, m34;
CGFloat m41, m42, m43, m44;
}
struct
CATransform3D
{
CGFloat m11(x缩放), m12(y切变), m13(旋转), m14();
CGFloat m21(x切变), m22(y缩放), m23(), m24();
CGFloat m31(旋转), m32(), m33(), m34(透视效果,要操作的这个对象要有旋转的角度,否则没有效果。正直/负值都有意义);
CGFloat m41(x平移), m42(y平移), m43(z平移), m44();
};
CATransform3DMakeTranslation
|
Returns a transform that translates by '(tx, ty, tz)'. t' = [1 0 0 0; 0 1 0 0; 0 0 1 0; txty tz 1]. |
CATransform3DTranslate
|
Translate 't' by '(tx, ty, tz)' and return the result: * t' = translate(tx, ty, tz) * t. |
CATransform3DMakeScale
|
Returns a transform that scales by `(sx, sy, sz)': * t' = [sx 0 0 0; 0 sy 0 0; 0 0 sz 0;0 0 0 1]. |
CATransform3DScale
|
Scale 't' by '(sx, sy, sz)' and return the result: * t' = scale(sx, sy, sz) * t. |
CATransform3DMakeRotation
|
Returns a transform that rotates by 'angle' radians about the vector '(x, y, z)'. Ifthe vector has length zero the identity transform is returned. |
CATransform3DRotate
|
Rotate 't' by 'angle' radians about the vector '(x, y, z)' and return the result. t' =rotation(angle, x, y, z) * t. |
也可以通过键值路径修改变换:
Table 4CATransform3D key paths
rotation.x
rotation.y
rotation.z
rotation
scale.x
scale.y
scale.z
scale
translation.x
translation.y
translation.z
translation
你不可以通过 Objective-C 2.0 的属性来设置结构域的值,比如下面的代码将会无法正常运行:
myLayer.transform.rotation.x=0;
替换的办法是,你必须通过 setValue:forKeyPath:或者 valueForKeyPath:方法,具体如下:
[myLayer setValue:[NSNumber numberWithInt:0] forKeyPath:@"transform.rotation.x"];
当我们使用 Cocoa的视图的时候,我们必须继承UIView并且重载函数drawRect:来显示任何内容。但是 CALayer实例可以直接使用,而无需继承子类。因为CALayer是一个键-值编码兼容的容器类,你可以在实例里面存储任意值,所以子类实例化完全可以避免。
你可以通过以下任何一种方法指定 CALayer实例的内容:
1、使用包含图片内容的CGImageRef来显式的设置图层的contents的属性。
CALayer *theLayer;
|
// create the layer and set the bounds and position
|
theLayer=[CALayer layer];
|
theLayer.position=CGPointMake(50.0f,50.0f);
|
theLayer.bounds=CGRectMake(0.0f,0.0f,100.0f,100.0f); |
// set the contents property to a CGImageRef
|
// specified by theImage (loaded elsewhere)
|
theLayer.contents=theImage;
|
2、指定一个委托,它提供或者重绘内容。
通过创建一个委托类实现下列方法之一:
displayLayer:或 drawLayer:inContext:
实现委托重绘的方法并不意味会自动的触发图层使用实现的方法来重绘内容。而是你要显式的告诉一个图层实例来重新缓存内容,通过发送以下任何一个方法setNeedsDisplay或 者 setNeedsDisplayInRect:的 消 息 , 或 者 把图 层 的needsDisplayOnBoundsChange属性值设置为 YES。
修改图层内容的位置
CALayer的属性contentsGravity允许你在图层的边界内容修改图层的contents图片的位置或者伸缩值。默认情况下,内容的图像完全填充层的边界,忽视自然的图像宽高比。
CALayer *theLayer = [CALayer layer];
theLayer.contents = (id)[UIImage imageNamed:@"1.png"].CGImage;
theLayer.frame = CGRectMake(100, 100, 500, 800);
theLayer.backgroundColor = [UIColor grayColor].CGColor;
/*
Position constant Description
kCAGravityTopLeft Positions the content image in the top left corner of the layer.
kCAGravityTop Positions the content image horizontally centered along the top edge of the layer.
kCAGravityTopRight Positions the content image in the top right corner of the layer.
kCAGravityLeft Positions the content image vertically centered on the left edge of the layer.
kCAGravityCenter Positions the content image at the center of the layer.
kCAGravityRight Positions the content image vertically centered on the right edge of the layer.
kCAGravityBottomLeft Positions the content image in the bottom left corner of the layer.
kCAGravityBottom Positions the content image centered along the bottom edge of the layer.
kCAGravityBottomRight Positions the content image in the top right corner of the layer.
*/
NSInteger i = 0;
switch (i) {
case 0:
{
theLayer.contentsGravity = kCAGravityTopLeft;
break;
}
case 1:
{
theLayer.contentsGravity = kCAGravityTop;
break;
}
case 2:
{
theLayer.contentsGravity = kCAGravityTopRight;
break;
}
case 3:
{
theLayer.contentsGravity = kCAGravityLeft;
break;
}
case 4:
{
theLayer.contentsGravity = kCAGravityCenter;
break;
}
case 5:
{
theLayer.contentsGravity = kCAGravityRight;
break;
}
case 6:
{
theLayer.contentsGravity = kCAGravityBottomLeft;
break;
}
case 7:
{
theLayer.contentsGravity = kCAGravityBottom;
break;
}
case 8:
{
theLayer.contentsGravity = kCAGravityBottomRight;
break;
}
default:
break;
}
[self.view.layer addSublayer:theLayer];
除了上诉常量之外,通过设置 contentsGravity属性为其他一个常量。图层的内容图片可以被向上或者向下拉伸, 仅当使用其他任何一个调整大小的常量的时候,contentsCenter属性才会对内容图片起作用。
CALayer *theLayer = [CALayer layer];
theLayer.contents = (id)[UIImage imageNamed:@"1.png"].CGImage;
theLayer.frame = CGRectMake(100, 100, 500, 800);
theLayer.backgroundColor = [UIColor grayColor].CGColor;
//
// Scaling constant Description
//
// kCAGravityResize Resize the content image to completely fill the layer bounds, potentially ignoring the natural
// aspect of the content. This is the default.
//
// kCAGravityResizeAspect Resize the content image to scale such that it is displayed as large as possible within the layer
// bounds, yet still retains its natural aspect.
//
// kCAGravityResizeAspectFill Resize the content image to scale such that it is displayed filling the layer bounds, yet retaining
// its natural aspect. This may cause the content to extend outside the layer bounds.
//
NSInteger j = 0;
switch (j) {
case 0:
{
theLayer.contentsGravity = kCAGravityResize;
break;
}
case 1:
{
theLayer.contentsGravity = kCAGravityResizeAspect;
break;
}
case 2:
{
theLayer.contentsGravity = kCAGravityResizeAspectFill;
break;
}
default:
break;
}
[self.view.layer addSublayer:theLayer];
第六章 动画 隐式的动画 和 显式的动画
核心动画提供了一套你可以在你应用程序里面使用的动画类的表现:
-
1CABasicAnimation提供了在图层的属性值间简单的插入。
-
1CAKeyframeAnimation 提供支持关键帧动画。你指定动画的一个图层属性的关键路径,一个表示在动画的每个阶段的价值的数组,还有一个关键帧时间的数组和时间函数。
-
1CATransition提供了一个影响整个图层的内容过渡效果。在动画显示过程中采用淡出(fade)、推出(push)、显露(reveal)图层的内容。 常用的过渡效果可以通过提供你自己定制的核心图像滤镜来扩展。
-
除了要指定显示的动画类型,你还必须指定动画的:
1间隔
1它的速度(它的插值如何分布在整个动画过程)
1动画循环时候的循环次数
1动画周期完成的时候是否自动的反转
1动画结束的时候它的可视化状态
动画类和 CAMediaTiming协议提供所有这些功能甚至更多的功能。
隐式的动画
虽然动画是持续的,但是设置新的目标值时会导致图层从当前状态动画过渡到新的目标值。
self.theLayer.position=CGPointMake(500.0,500.0);
self.theLayer.opacity=0.5;
self.theLayer.frame = CGRectMake(0,0,100,100);
隐式动画使用动画属性中默认指定的动画时间,除非该时间已经被隐式或者显式的修改过。阅读“重载覆盖隐式动画时间”获取更多详情。
事务的嵌套
显式事务可以被嵌套,允许你禁用部分动画的行为或者在属性被修改的时候产生的动画使用不同的时间。仅当最外层的事务被提交的时候,动画才会发生。
// 两套动画嵌套,会同时执行,第一个动画5秒,第二个动画5秒,两套一起执行,总共5秒
// first begin
[CATransaction begin];
[CATransaction setValue:[NSNumber numberWithFloat:5.0f] forKey:kCATransactionAnimationDuration];
self.theLayer.position = CGPointMake(0, 0);
// second begin
[CATransaction begin];
[CATransaction setValue:[NSNumber numberWithFloat:5.0f] forKey:kCATransactionAnimationDuration];
self.theLayer.zPosition=200.0;
self.theLayer.opacity=0.0;
[CATransaction commit];
// second end
[CATransaction commit];
// first end
第九章 布局核心动画的图层
NSView提供了经典的“stutsand springs”模式,用于视图调整大小的时候把关联到它父图层的视图重新调整位置。图层支持该模式,而且 Mac OS X 上面的核心动画提供了一个更通用的布局管理器机制,允许开发者自己写他们自己的布局管理器。可以为图层定制一个布局管理器(它通常实现CALayoutManager协议),负责给图层的子图层提供布局功能。
iOS 注意:iOS 的 CALayer 类仅提供“stuts and springs”模式,不提供定制的布局管理器。然而如果你想人工修改关联到特别视图的图层的位置的话,你可以重载相应视图的layoutSubviews 方法,在这里面实现你定制的布局代码。你可以查看“iOS 视图编程指南(ViewProgramming Guide for iOS)”来获取更多关于如何在 iOS 应用里面基于视图的布局方法。
第十章 核心动画的键-值编码扩展
CAAnimation和 CALayer类扩展了 NSKeyValueCoding协议,给键添加默认值,扩展了封装协议,支持CGPoint、CGRect、CGSize和 CATransform3D关键路径。
CALayer和 CAAnimation都是键-值编码兼容的容器类,允许你修改属性键对应
的值。即使键为“someKey”对应的属性没有被定义,你也可以给“someKey”的键
设置一个值,如下:
[theLayer setValue:[NSNumber numberWithInteger:50] forKey:@"someKey"];
你可以通过下面的代码检索“someKey”对应的值:
someKeyValue=[theLayer valueForKey:@"someKey"];
Mac OS X 注意:在 Mac OS X 上面,CALayer 和 CAAnimation 类支持 NSCoding 协议,会自动归档这些你设置的额外键。
核心动画添加的键值编码约定,允许一个类在被使用时键没有被设置相应值的时候提供默认值。CALayer 或CAAnimation支持该约定,通过使用方法defaultValueForKey:
设置默认值的方法:
1创建相应的子类
1重载defaultValueForKey:。
1子类实现相应的键参数检查并返回适当的默认值。
+ (id)defaultValueForKey:(NSString *)key
{
if ([key isEqualToString:@"masksToBounds"]){
return [NSNumber numberWithBool:YES];
 }
return [super defaultValueForKey:key];
}
10.4支持结构字段的关键路径
CAAnimation提供支持使用关键路径访问选择的结构字段。这在为动画关键路径指定结构字段的时候非常有帮助,同时你可以使用setValue:forKeyPath:和valueForKeyPath来设置和读取相应的值。
你不可以通过 Objective-C 2.0 的属性方法来指定一个结构字段的关键路径。如下的代码是无法正常执行的:
myLayer.transform.rotation.x=0;
相反你必须使用setValue:forKeyPath:或者 valuForKeyPath:,如下:
[myLayer setValue:[NSNumber numberWithInt:0] forKeyPath:@"transform.rotation.x"];
第十一章 图层样式属性
11.1几何属性
11.2背景属性
图层渲染它的背景。你可以定义背景的颜色,也可以定义图像滤镜。
11.3 图层内容
如果你设置了图层内容,则它将会被渲染出来。图层的内容可以通过 Quartz 图像环境、OpenGL、QuickTime 或者 Quartz Composer 来创建。
11.4 子图层内容
通常图层具有层次结构的子图层。这些子图层依据和它父图层的几何关系被递归的渲染到界面。 父图层的 sublayerTransform 属性根据它的 anchorPoint 属性被应用到每个子图层。
11.5 边框属性
图层可以使用指定的颜色和宽度来显示一个额外的边框
11.6 滤镜属性
一组核心图像的滤镜可以被应用到图层上面。滤镜影响图层的边框、内容和背景。
11.7 阴影属性
一个图层可以显示阴影,指定它的不透明度,颜色,偏移量和模糊半径。
11.8 不透明属性
11.9 混合属性
图层的混合滤镜可以使用来组合图层层与层之间的背后内容。默认情况下,使用
源的图层是混合的。
11.10 遮罩属性
你可以指定一个图层作为遮罩,甚至可以修改如何渲染图层的显示。当图层是混合的时候,遮罩图层的不透明度决定了遮罩的效果。
图 10 显示了示例图层混合后被一个遮罩图层作用的效果。
以下 CALayer 的属性为一个图层指定遮罩:
iOS 注意:mask 属性仅在 iOS 3.0 之后才支持。