核心动画的基础接口以及为拥有Layer的View作的动画扩展接口,使得为Layer制做复杂动画变得简单化。例如改变Layer的frame的size、改变Layer在屏幕上的position、应用旋转transform、或者改变它的opacity。经过使用核心动画,建立一个动画效果将会变得简单的就像修改属性同样,可是咱们也能显式的建立和设置动画参数。
关于建立更多高级动画能够参见Advanced Animation Tricks(后续会有译文)。html
根据须要,咱们能够选择显式或者隐式的执行简单的动画。隐式的动画使用默认的速度调节和动画属性来执行动画;相反,隐式动画须要咱们使用核心动画对象配置相应的属性。所以当咱们想要使用少许代码和默认定时速度作动画过分改变的时候,隐式动画是个不错的选择。ios
简单的动画意味着改变Layer的属性,和让核心动画是这些改变随着时间发生变化。Layers定义了许多可以影响可视化外观的属性,改变这些属性之一就会引发相应的外观动画性的变化;例如,改变Layer的opacity由1.0到0.0将会引发Layer渐渐隐藏(淡出)并变透明。算法
重要提示:咱们有时能够直接使用核心动画的接口为Layer-backed View(iOS 内的view均可称为此种view,前面章节有说明)作动画,这么作经常须要一些额外的步骤,更多关于如何使用与Layer-backed views结合的动画能够参见如何为Layer-Backed View作动画。数组
为了触发隐式动画,咱们只须要去更新Layer对象的属性。当更改图层树上的Layer对象的时候,Layer的属性将会马上变动为咱们调整的值,然而Layer对象的外观不会马上改变为咱们设置的值;相反,核心动画使用咱们调整的值做为触发器来建立和规划一个或多个隐式动画,而后核心动画并执行这些动画。所以,像代码3-1中调整属性值将会引发核心动画建立动画对象,并规划那个动画到下个更新循环开始执行。app
Listing 3-1 Animating a change implicitlyide
theLayer.opacity = 0.0;
为了制做和隐式动画同样的动画,咱们也可经过显示的使用动画对象,建立一个CABasicAnimation 对象和使用那个对象配置动画参数。在将动画对象添加到Layer上以前,咱们能够为动画对象设置开始和结束值、改变更画周期,或者任何其余的动画参数。代码3-2展现了如何经过动画对象将Layer渐隐。当建立动画对象后,咱们指定要作动画的属性的Key path,而后设置动画参数。为了执行动画,咱们使用addAnimation:forKey:方法将动画对象添加到Layer上。函数
Listing 3-2 Animating a change explicitlyoop
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;
提示:当建立显示动画的时候,建议为动画对象设置fromValue属性值,若是咱们不指定这个值,核心动画将会使用Layer的当前值做为动画的开始值,若是咱们将这个属性值设定的和动画的最终值一致,那么将不会产生咱们想要的动画效果。布局
和隐式动画不同的是,隐式动画将会更改Layer对象的值,显示动画不会修改图层树上的数据。显示动画仅仅产生动画效果。在动画的结束后,核心动画将会从Layer上移除动画对象并使用Layer的当前值从新绘制。若是咱们想要显示动画的改变发生到Layer上,那么咱们必须也更新Layer的属性,就像3-2中指出的同样。动画
隐式和显示动画一般在当前runloop循环结束后就开始执行,为了动画对象的执行,当前线程必须有一个runloop。若是咱们改变多个属性,若是为Layer添加多个动画对象,全部这些属性将会同时发生动画。例如咱们经过同时设置两个动画,就可使得隐藏一个Layer和将Layer移动到屏幕外面的同时发生。咱们一能够设置动画对象在某个特殊的时间点开始。关于更多的修改动画的时间函数参见 Customizing the Timing of an Animation(后续会有译文)。
属性动画经过改编属性从开始值到结束值发生动画, CAKeyframeAnimation 对象将会经过设定线性或者非线性目标值点集合的方式制做动画。一个关键帧动画由目标集合点,和与单个目标点对应的时间点的集合组成。最简单的配置就是,咱们仅仅经过使用数组指定这两种值。对于改变Layer的position来讲,咱们也能够指定它沿着path发生变化。动画对象取咱们指定的关键帧并经过一个值到下一个值在给定的时间片刻上进行插值创建动画。
图3-1显示了Layer的position属性5s的动画。Position是沿着一条path作的动画,就是使用CGPathRef数据类型制定的path。对应的代码见代码3-3。
代码3-3展现了如何实现图3-1中动画的代码。在这个例子中,path对象是被用来定义每帧动画中Layer的position。
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. theAnimation=[CAKeyframeAnimation animationWithKeyPath:@"position"]; theAnimation.path=thePath; theAnimation.duration=5.0; // Add the animation to the layer. [theLayer addAnimation:theAnimation forKey:@"position"];
关键帧的值是关键帧动画最重要的一部分。关键帧的值明确了动画执行的路线。主要指定关键帧值的方式是使用数组,可是对于当数组中包含CGPoint数据类型的时候(例如Layer的anchorPoint和position属性),咱们也能够指定CGPathRef数据类型代替。
当指定数组值的时候,数组中应该放的数据类型取决于要作动画的属性。咱们能够将某些对象直接添加到数组中;可是有些类型必须先转换到id对象类型在添加以前,全部的标量类型和结构体必须先包装成对象,例如:
对于对应CGPoint数据类型的属性,咱们能够建立point的数组(先包装成NSValue对象)或者使用CGPathRef对象指定动画的路线。当咱们指定point的数组的时候,关键帧动画对象建立的动画将会走直线在相邻的点。当咱们指定CGPathRef对象,动画从路径的起点开始,并沿着他的轮廓走,若是是曲线,它也可以沿着曲线的路径走。咱们也可使用非闭合或者闭合的路径。
关键帧的时间函数和空间位置是比基本动画(basic animations)更复杂的,这里有几个供控制它们的属性:
若是咱们想要本身控制时间函数,须要采用 kCAAnimationLinear或kCAAnimationCubic 模式和keyTimes以及timingFunctions属性。keytimes属性指定应用于对应帧值的时间点。timeingFunctions用于控制全部时间的插值,它将容许在每一个片断咱们应用缓入或者缓出。若是咱们不指定timingFunctions时间函数将会是线性的。
正常状况下动画会运行到动画完成,可是若是有须要,咱们可以经过如下方式提早移除它们:
注意:咱们不能从Layer直接移除隐式动画。
当咱们从Layer上面移除动画的时候,核心动画将会响应——使用Layer当前的值重绘Layer。由于一般是动画的最终值(end values),这可能引发Layer的样貌发生跳跃性的变化。若是咱们想要Layer的样貌保持在动画的最后一帧,咱们可使用呈现树上的Layer对象获取最终值(若是是移除操做也能够称为,动画当前值)并设置他们这些值到图层树。
更多关于临时暂停动画可参见代码5-4(后续会有译文)。
若是咱们想要将多个动画同时应用到Layer对象,咱们能够将他们绑定在一块儿经过使用CAAnimationGroup对象,group对象能够以简单的配置简化多个动画对象的管理。设置到group对象的时间函数和duration值将会覆盖单个动画对象对应的值。
代码3-4展现了如何使用一个group对象以相同的时间函数和相同时间周期的实现两个边框相关的动画。
Listing 3-4 Animating two animations together
// 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"];
Transaction对象可以提供将动画组合在一块儿的更高级方式。Transcation经过容许咱们建立嵌套的动画集和为每一个动画关联不一样动画参数,也所以Transcation更灵活,更多关于如何使用Transaction对象,可参见 Explicit Transactions Let You Change Animation Parameters(后续会有译文)。
核心动画提供获取动画开始和结束事件的支持。这些通知对于动画辅助任务来讲是很好的时间点。例如咱们能够借助获取到开始通知时去设置一些相关联的状态信息并使用对应的结束通知撤销这些状态。
有一下两种不一样的获取方式:
若是咱们想要去将两个动画衔接在一块儿,实现当一个结束另一个就开启,不要使用动画通知,相反的应该使用动画对象的beginTime属性去开启每个动画在指望的时间点。为了将两个动画先后衔接在一块儿,设置第二个动画的start为第一个动画的end时间。更多关于动画和时间值的信息参见Customizing the Timing of an Animation(后续会有译文)。
若是Layer属于Layer-backed view,动画建立的推荐方式是使用经过UIKit或AppKit提供的基于View的动画接口。经过使用核心动画接口,有许多方式能够为Layer作动画,可是如何建立这些动画取决于所在的目标平台(iOS 、OSX)。
由于iOS中的view一直都有一个内在的Layer,UiView类直接从layer对象直接获取许多数据,这就致使咱们为Layer作的调整也会在View对象上自动提现出来,这就意味着咱们可使用核心动画或者UIView的接口来实现这些调整。
基于Layer-backed View,若是咱们想要使用核心动画建立动画,咱们必须在基于view的动画block内部发起全部的核心动画的调用。UIView类默认禁用了Layer动画,可是在动画bolcks中能够激活,所以任何在bolcks外的Layer调整将不会发生动画。代码3-5展现了基于Layer-backed View内如何为Layer制做opacity隐式动画,和position显示动画。在这个例子中,myNewPosition变量是被提早计算并被block捕获到的。两个动画在同一时间开始,可是opacity动画一默认的时间函数运行,position动画以他动画对象所指定的时间函数运行。
Listing 3-5 Animating a layer attached to an iOS view
[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"]; }];
若是使用基于约束的布局规则管理views的position,那么做为配置动画的一部分,咱们必须移除任何影响动画的约束。约束影响任何咱们为view的position或size作的调整,他们经常影响view之间以及view和他们子view的关系;若是咱们为这些带有约束的view作动画,咱们须要移除这些约束,并应用咱们须要的新的约束。
更多关于约束和如何使用他们管理views的layout的信息参见Auto Layout Guide。