动画层内容
Core Animation提供的基础结构使创建应用程序层的复杂动画变得容易,并且可以扩展到拥有这些层的所有视图。例如,更改图层框架矩形的大小,更改其在屏幕上的位置,应用旋转变换或更改其不透明度。使用Core Animation,启动动画通常与更改属性一样简单,但是您也可以创建动画并显式设置动画参数。
有关创建更多高级动画的信息,请参见“ 高级动画技巧”。
动画化对图层属性的简单更改
您可以根据需要隐式或显式执行简单的动画。隐式动画使用默认的时间和动画属性执行动画,而显式动画需要您自己使用动画对象配置这些属性。因此,隐式动画非常适合您希望无需大量代码即可进行更改且默认计时适合您的情况。
简单的动画包括更改图层的属性,并让Core Animation随时间动画化那些更改。图层定义了许多影响图层可见外观的属性。更改这些属性之一是动画外观更改的一种方法。例如,将图层的不透明度从更改1.0为0.0会导致图层淡出并变为透明。
重要说明: 尽管有时您可以使用Core Animation界面直接为基于图层的视图设置动画,但是这样做通常需要额外的步骤。有关如何将Core Animation与层支持的视图结合使用的更多信息,请参见如何对层支持的视图进行动画处理。
触发隐式动画,您需要做的就是更新图层对象的属性。在层树中修改层对象时,这些对象会立即反映出您的更改。但是,图层对象的视觉外观不会立即改变。相反,发生的情况是Core Animation使用您的更改作为触发来创建和安排一个或多个隐式动画以供执行。因此,进行类似于清单3-1中的更改将使Core Animation为您创建一个动画对象,并安排该动画在下一个更新周期开始运行。
清单3-1 隐式地为更改添加动画
theLayer.opacity = 0.0;
要使用动画对象显式进行相同的更改,请创建一个CABasicAnimation对象,然后使用该对象配置动画参数。在将动画添加到图层之前,可以设置动画的开始和结束值,更改持续时间或更改任何其他动画参数。清单3-2显示了如何使用动画对象淡出图层。创建对象时,可以为要设置动画的属性指定关键路径,然后设置动画参数。要执行动画,可以使用addAnimation:forKey:方法将其添加到要设置动画的图层中。
清单3-2 明确显示更改动画
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”];
//将图层中的实际数据值更改为最终值。
theLayer.opacity = 0.0;
提示: 创建显式动画时,建议始终fromValue为动画对象的属性分配一个值。如果未为此属性指定值,则Core动画会使用图层的当前值作为起始值。如果您已经将该属性更新为其最终值,则可能不会产生所需的结果。
与隐式动画更新图层对象的数据值不同,显式动画不会修改图层树中的数据。显式动画仅生成动画。在动画结束时,Core Animation会从图层中删除动画对象,并使用其当前数据值重画该图层。如果您希望永久更改来自显式动画的更改,则还必须更新图层的属性,如上例所示。
隐式和显式动画通常在当前运行循环周期结束后开始执行,并且当前线程必须具有运行循环才能执行动画。如果更改多个属性,或者将多个动画对象添加到图层,则所有这些属性更改将同时进行动画处理。例如,您可以通过同时配置两个动画来淡出图层,同时将其移出屏幕。但是,您也可以将动画对象配置为在特定时间开始
使用关键帧动画更改图层属性
基于属性的动画将属性从开始值更改为结束值,而CAKeyframeAnimation对象使您可以以线性或不线性的方式遍历一组目标值。关键帧动画由一组目标数据值和应达到每个值的时间组成。在最简单的配置中,您可以使用数组指定值和时间。对于图层位置的更改,您还可以使更改遵循路径。动画对象采用您指定的关键帧,并通过在给定的时间段内从一个值插入下一个值来构建动画。
图3-1显示了图层position属性的5秒钟动画。对该位置进行动画处理以遵循使用CGPathRef数据类型指定的路径。清单3-3显示了此动画的代码。


指定关键帧值
关键帧值是关键帧动画中最重要的部分。这些值定义了动画执行过程中的行为。指定关键帧值的主要方式是作为对象数组,但是对于包含CGPoint数据类型(例如图层anchorPoint和position属性)的值,可以CGPathRef改为指定数据类型。
指定值数组时,您要放入数组中的内容取决于属性所需的数据类型。您可以将一些对象直接添加到数组中。但是,必须先将某些对象强制转换为对象id,并且所有标量类型或结构都必须由对象包装。例如:
对于具有的属性CGRect(例如bounds和frame属性),请将每个矩形包装在一个NSValue对象中。
对于图层的transform属性,将每个CATransform3D矩阵包装在一个NSValue对象中。对此属性进行动画处理将使关键帧动画依次将每个变换矩阵应用于该图层。
对于borderColor属性,将每个CGColorRef数据类型转换为该类型,id然后再将其添加到数组中。
对于带有CGFloat值的属性,将每个值包装在NSNumber对象中,然后再将其添加到数组中。
在设置图层contents属性的动画时,请指定CGImageRef数据类型的数组。
对于采用CGPoint数据类型的属性,可以创建点数组(包装在NSValue对象中),也可以使用CGPathRef对象指定要遵循的路径。指定点数组时,关键帧动画对象会在每个连续点之间绘制一条直线,并遵循该路径。指定CGPathRef对象时,动画从路径的起点开始并遵循其轮廓,包括沿任何曲面。您可以使用开放路径或封闭路径。
指定关键帧动画的时间
关键帧动画的定时和步调比基本动画的定时和步调更为复杂,并且可以使用一些属性来控制它:
该calculationMode属性定义了用于计算动画时间的算法。此属性的值影响其他与时序相关的属性的使用方式。
线性和三次动画(即calculationMode属性设置为kCAAnimationLinear或kCAAnimationCubic的动画)使用提供的时间信息来生成动画。这些模式使您可以最大程度地控制动画时间。
节奏动画(即,calculationMode属性设置为kCAAnimationPaced或的动画)kCAAnimationCubicPaced不依赖于keyTimes或timingFunctions属性提供的外部计时值。取而代之的是,隐式计算时间值,以使动画具有恒定的速度。
离散动画(即,calculationMode属性设置为kCAAnimationDiscrete的动画)会导致动画属性从一个关键帧值跳到下一个关键帧值而没有任何插值。此计算模式使用keyTimes属性中的值,但忽略该timingFunctions属性
该keyTimes属性指定应用每个关键帧值的时间标记。仅当计算模式设置为,或时kCAAnimationLinear,才使用此属性。它不适用于节奏动画。kCAAnimationDiscretekCAAnimationCubic
该timingFunctions属性指定用于每个关键帧段的时序曲线。(此属性替换继承的timingFunction属性。)
如果要自己处理动画时间,请使用kCAAnimationLinear或kCAAnimationCubic模式以及keyTimes和timingFunctions属性。的keyTimes在时间上要应用每个关键帧值定义的点。所有中间值的时序均由时序功能控制,可让您将缓入或缓出曲线应用于每个段。如果未指定任何计时功能,则计时是线性的。
在运行时停止显式动画
动画通常会运行到完成为止,但是如果需要,您可以使用以下一种技术来将其提前停止:
要从图层中删除单个动画对象,请调用图层的removeAnimationForKey:方法以删除您的动画对象。此方法使用传递给该addAnimation:forKey:方法的关键点来标识动画。您指定的密钥不能为nil。
要从图层中删除所有动画对象,请调用图层的removeAllAnimations方法。此方法立即删除所有正在进行的动画,并使用其当前状态信息重绘该图层。
注意: 您不能直接从图层中删除隐式动画。
从图层中删除动画时,Core Animation会通过使用其当前值重画该图层来做出响应。因为当前值通常是动画的最终值,所以这可能会导致图层的外观突然跳跃。如果希望图层的外观保持在动画最后一帧的位置,则可以使用表示树中的对象来检索这些最终值,并将其设置在图层树中的对象上。
一起对多个更改进行动画处理
如果要同时将多个动画应用于图层对象,则可以使用一个CAAnimationGroup对象将它们组合在一起。通过提供一个配置点,使用组对象可简化对多个动画对象的管理。应用于组的时间和持续时间值会覆盖各个动画对象中的相同值。
清单3-4显示了如何使用动画组在相同的时间和相同的时间执行两个与边框相关的动画。
// 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"];
检测动画的结束
核心动画为检测动画何时开始或结束提供支持。这些通知是执行与动画相关的任何内务处理的好时机。例如,您可以使用开始通知来设置一些相关的状态信息,并使用相应的结束通知来拆除该状态。
可以通过两种不同的方式来通知动画状态:
使用setCompletionBlock:方法将完成块添加到当前事务中。当事务中的所有动画完成时,事务将执行您的完成块。
将委托分配给您的CAAnimation对象,并实现animationDidStart:和animationDidStop:finished:委托方法。
如果要将两个动画链接在一起,以便一个动画在另一个动画结束时开始,请不要使用动画通知。而是使用beginTime动画对象的属性在所需的时间开始每个动画对象。要将两个动画链接在一起,请将第二个动画的开始时间设置为第一个动画的结束时间。
如何对图层支持的视图进行动画处理
如果层属于层支持的视图,则建议的创建动画的方法是使用UIKit或AppKit提供的基于视图的动画接口。有多种方法可以使用Core Animation接口直接为图层设置动画,但是如何创建这些动画取决于目标平台。
在iOS中修改图层的规则
由于iOS视图始终具有基础层,因此UIView该类本身直接从该层对象获取大部分数据。结果,您对图层所做的更改也将自动被视图对象反映。此行为意味着您可以使用“核心动画”或UIView界面进行更改。
如果要使用Core Animation类来启动动画,则必须从基于视图的动画块中发出所有Core Animation调用。该UIView班由默认值,但重新启用这些动画块内部禁用层动画。因此,您在动画块之外进行的任何更改都不会被动画化。清单3-5显示了如何隐式更改图层的不透明度和显式更改其位置的示例。在此示例中,myNewPosition变量是预先计算的,并由块捕获。两种动画同时开始,但不透明度动画以默认定时运行,而位置动画以其动画对象中指定的定时运行。
[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"];
}];
切记在动画中更新视图约束
如果使用基于约束的布局规则来管理视图的位置,则在配置该动画时,必须删除所有可能干扰动画的约束。约束会影响您对视图的位置或大小所做的任何更改。它们还影响视图及其子视图之间的关系。如果要对这些项目中的任何一项进行动画处理,则可以删除约束,进行更改,然后应用所需的新约束。
网友评论