Core Animation 文档翻译 (第六篇)—高级动画技巧

 

前言


配置属性动画或者关键帧动画的方式是多种多样的。须要同时执行多个动画或者顺序执行多个动画的APP,能够经过高级的方式同步这些动画的timing或者将这些动画绑定在一块儿。咱们也可使用其余类型的动画对象来建立可视化的transitions和别的有趣的动画效果。缓存

 

过渡动画支持Layer可见性的变化


就像本级标题名字所说同样,一个transition动画对象为Layer建立一个动画性的过渡效果。transistion对象最经常使用的方法就是以协调的方式让一个Layer动画形式的出现,并让另一个Layer动画形式的消失。和属性动画不同,属性动画是改变Layer的一个属性;而transition动画操做layer缓存的image用来建立可视化效应,经过只调整属性这些可视化效应是很难或者几乎不愿能完成的。标准的transition类型能够用来实现渐显、push、移除或者交叉渐隐动画。在OSX上,咱们也可使用Core image filter建立具备特殊效应的transitions,例如擦拭、卷页、波纹或者自定义的其余效果。app

为了执行transition动画,咱们能够建立CATransition对象并将其添加到相关的Layers。咱们在使用transition对象的时候能够指定transition的类型、开始和结束进度点。开始动画前,能够设置开始和结束进度值,这两个值可让咱们的transition动画看起来像从开始值开始,和结束值结束。函数

代码5-1展现了如何在两个View之间建立push 过渡动画。在这个例子中,myView1和myView2是在同一个父视图上相同的position,而且myView1是可见的在最初。动画效果为myView1想作滑出知道彻底隐藏,同时myView2从右边滑入知道彻底显示。为了确保在动画的结束时候两个view相应的可见性是正确的,咱们须要更新两个view的hidden属性。性能

 

代码5-1在iOS中两个view之间过分动画
CATransition* transition = [CATransition animation];
transition.startProgress = 0;
transition.endProgress = 1.0;
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromRight;
transition.duration = 1.0;
 
// Add the transition animation to both layers
[myView1.layer addAnimation:transition forKey:@"transition"];
[myView2.layer addAnimation:transition forKey:@"transition"];
 
// Finally, change the visibility of the layers.
myView1.hidden = YES;
myView2.hidden = NO;

 

当两个layer都须要相同的过分动画时候,咱们可让他们使用相同的transition对象。使用相同的transition对象也能简化代码。动画

 

自定义动画时间函数


时间控制函数是动画的重要部分。经过核心动画中CAMediaTiming协议的方法和属性,咱们能够为动画指定精确的时间信息。CAAnimation类遵照该协议,所以咱们可以指定动画对象的时间信息,隐式动画对象默认封装了这些信息,并优先使用默认的信息。spa

对于如何理解时间信息和动画时,理解Layer对象和time之间关系是很重要的。每一个Layer有他们本身的局部时间,Layer使用本身的局部时间来管理动画时间。一般状况下,两个不一样Layer的局部时间是很是接近的,以致于在为这两个Layer指定相同的时间值时,用户也察觉不到。然而,Layer的局部时间可以被它的父Layer和它自身的时间参数所修改。例如,改变Layer的[speed]属性可以引发Layer(和他的sublayer)的动画的duration发生成比例的变化。code

为了帮助咱们确保时间值是恰当的,CALayer类定义了convertTime:fromLayer: and convertTime:toLayer:方法。咱们可使用这些方法将一个修正的时间值转换为layer的局部时间,或者将一个layer的时间值转换到另一个Layer。这两个方法涉及到时间相关的属性并返回一个值,咱们将这个值能够用于别的layer,这两个方法所涉及到的时间属性也会影响layer的局部时间。代码5-3展现了按期用于得到一个layer的当前局部时间。经过CACurrentMediaTime函数能够获取计算机当前时间,同时可将这个时间用于转换出Layer的局部时间。orm

 

代码5-3过的Layer的本地时间
CFTimeInterval localLayerTime = [myLayer convertTime:CACurrentMediaTime() fromLayer:nil];

 

一旦咱们有了相对于layer局部时间的值,咱们可使用该值去更新动画对象或Layer的时间相关的属性。经过设置这些时间属性,咱们能够得到许多有趣的动画行为,这些属性包含如下几种:对象

  • 使用beginTime属性设置动画的开始时间。一般,动画在下个更新循环开始执行。咱们可使用beginTime参数去延迟几秒动画的开始。将两个动画顺序的关联在一块儿的方法就是,将一个动画的beginTime和另一个动画的结束值设置为相同的值。
    若是咱们延迟动画的开始时间,咱们也应该设置fillModel属性的值为kCAFillModeBackwards。这个模式将会使Layer显式动画的开始值,及时图层树上的Layer对象具备不一样的值。若是不设置这个模式,咱们将会看到一个到最终值跳跃性的显式在动画开始执行前。其余的模式也是可用的。
  • autoreverses属性将会引起动画以被指定的duration返回动画的开始值。咱们将这个属性与repeatCount属性结合起来能够实如今开始值和结束值之间来回作动画。若是autoreversing为YES并为repeatCount属性设置整数值(例如1.0),那么将会引发动画中止在开始值;添加额外的一半动画(例如设置为1.5)将会使得动画中止在结束值的位置。ci

  • 在组动画中使用timeOffset属性可以让一些动画在组内某些动画以后开始。

 

暂停和重启动画


为了暂停动画,咱们能够利用Layer遵照的CAMediaTiming协议,并设置Layer动画的speed为0.0。将speed设置为0将引发动画暂停,直到咱们改变这个值为非0值动画才会结束暂停。代码5-4展现了简单的示例关于如何暂停和在暂停后重启动画。

 

5-4暂停和重启Layer的动画
-(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;
}

 

显式动画帮助咱们改变更画的参数


为Layer作的每个改变必须是transaction的一部分。[CATransaction]类管理动画的建立、将动画组合在一块儿并将组合的动画以恰当的时间执行。大部分状况下,咱们不须要建立本身的transactions。不管什么时候你为Layer添加显式和隐式动画,核心动画自动建立隐式transaction。然而,咱们也能建立显式transactions去更准确的管理这些动画。

使用CATransaction类的方法,咱们能够建立和管理transactions。调用begin类方法开始(隐式的建立)新的transaction;调用commit类方法结束transaction。在这两个方法之间调用咱们想要做为transaction其中的变化。例如咱们使用代码5-5变化layer的两个属性。

 

5-5建立显式的transaction
[CATransaction begin];
theLayer.zPosition=200.0;
theLayer.opacity=0.0;
[CATransaction commit];

 

使用transactions最主要的缘由就是在transaction的beginTime和commit中间,咱们能够改变duration,timing函数和其余参数。咱们可以也可以为transaction关联一个完成后执行的block,方便咱们的APP可以在这组动画结束后的到通知。改变更画的参数,须要经过修改在使用setValue:forKey:方法修改transaction字典里面对应的key。例如,改变默认duration为10秒,咱们应该改变kCATransactionAnimationDuration key,例如代码5-6展现

 

5-6改变更画的默认duration
[CATransaction begin];
[CATransaction setValue:[NSNumber numberWithFloat:10.0f]
                 forKey:kCATransactionAnimationDuration];
// Perform the animations
[CATransaction commit];

 

当咱们想要为不一样的动画集合提供不一样的值时,咱们能够嵌套transactions。若是想要嵌套,只须要在begin类方法以后再次调用begin方法。每个begin调用必须和-个commit方法对应。仅当咱们提交最后一个最外层的commit方法时,核心动画才会开始相关的动画。

代码5-7展现了两个transaction的嵌套。在这个例子中这个内层的和外层的transaction改变相同的动画参数,可是使用不一样的值。

 

5-7嵌套显式的transaction
[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

 

为动画添加观看者视角


APP能够在三个维度控制Layer;简单的核心动画所展现的Layers是使用了平面投射,本质就是核心动画将3维空间投射到2维平面上了。默认状况下,具备相同尺寸和不一样zPosition的Layers看起来像是同样大的,即便他们在Z轴上的坐标是不一样的,也就是说咱们不能想正常的人眼视角观看这些三维场景。然而,咱们能够经过修改Layers的transformation矩阵,加入人眼观看视角。
当调整一个三维场景的视角时,咱们须要调整superlayer的sublayerTransform矩阵(superlayer包含这些可被看到的layers),经过调整superlayer可以简化代码的工做量(若是不经过调整superlayer那么咱们就须要把相同的视角相关信息应用到全部的子Layer),同时他也确保了视角是正确应用到同级的sublayers上(同级的sublayers可能在不一样的平面重叠交叉)。

代码5-8展现了为父Layer建立简单的视角transform。在这种状况下,自定义的人眼视角的变化将会改变沿着Z轴到Layer的距离。一般为了保证Layers以指望的方式,咱们为人眼视角指定一个正数值。数值越大看到的越远,数值越小看到的会越细致。

 

代码5-8为父Layer添加视角transform
CATransform3D perspective = CATransform3DIdentity;
perspective.m34 = -1.0/eyePosition;
 
// Apply the transform to a parent layer.

 

在相似之上配置了父Layer状况下,咱们能够改变任何子Layer的zPosition属性,并观察它们的尺寸(在基于它们到人眼位置)是如何变化的。

相关文章
相关标签/搜索