iOS-核心动画时序控制(译)

这是我第一次翻译国外大神的文章。为了行文通顺,某些地方没有完全遵照原文。末尾附有自己的一些私货。
原文链接如下:
http://ronnqvi.st/controlling-animation-timing/
如有疏漏,敬请指出,不胜感激。

概述

在iOS的动画框架中,有一个叫做CAMediaTiming的协议,它由CAAnimation实现,而后者是CABasicAnimation和CAKeyframeAnimation的基类。所有和时序相关的属性:duration, beginTime, repeatCount等等都是从这个协议中来的。总体来说,该协议定义了8个属性,这8个属性可以通过不同的组合方式来精确控制动画时序。苹果官方文档对每个属性的介绍都非常简略,因此阅读官文会比阅读这篇博客更快,但是我个人认为,有关时序的问题,最好还是结合图表来理解。因此花费一些篇幅是有必要的。

图解CAMediaTiming

为了解释和时序有关的各个属性,我现在要做一个颜色变化的动画(橙->蓝)。下图中的格子表示一段动画从开始到结束的整个时间线,而其中每一格代表时间线中的一秒。你可以看到整个动画过程中任意时刻的颜色。

duration

下图展示了设置duration=1.5时的情景。

WX20170317-134617.png

CAAnimation会在动画结束后默认从layer上移除,该过程同样如图上所示。一旦animation对象到达了它的“最终值”(animation的值通过“插值”法进行变化。关于“最终值”的解释会附在文末。——译者注),它就会从layer上移除。如果layer原本的颜色是橙色(注意,不是说它的fromValue是orangeColor——译者注),那么在动画结束后layer将变回橙色。在该图示中,layer的原本颜色是白色,所以在动画添加到layer上1.5秒后,layer就会变成白色。

beginTime

如果我们再加上beginTime这个属性会更好理解一些。如图:

图2.png

duration被设置为1.5秒,beginTime被设置为currentTime(CACurrentMediaTime() + 1),所以动画将在Animation对象被添加到layer上1秒后动画开始执行。2.5秒后结束。
如果要让layer在动画开始前显示Animation的fromValue,你可以设置fillMode为kCAFillModeBackwards,来让动画“向后填充”。图示如下:

图3.png

autoreverses

autoreverses属性可以让动画从“起始值”执行到“最终值”,然后再反过来,从“终止值”执行到“起始值”。因此,整个动画执行时间将会是duration 的2倍。

图4.png

repeatCount

repeatCount可以将动画重复执行2次(如下图所示)甚至任意次(你可以设置repeatCount为1.5,让动画执行一次半)。一旦动画执行到了“最终值”它会立即回到“起始值”然后重新开始执行。请读者将autoreverses和repeatCount属性做一个对比。

图5.png

repeatDuration

repeatDuration作用和repeatCount类似,但是却很少用到。它会单纯地在给定的时间内(尽可能地)重复动画。下图所示为repeatCount=2时的情景。如果repeatDuration小于duration,则动画会提前结束(即动画的真正执行时间取决于repeatCount。——译者注)。

图6.png

以上属性都可以组合使用。

图7.png

speed

speed是一个更为有趣的时序属性。如果duration=3,speed=2,则动画执行时间会是1.5秒。(即执行时间=speed * duration)。

图8.png

如果只是为了控制一个简单动画的速度,你当然可以通过设置beginTime和duration来达到目的。但是speed属性的强大之处在于:

  • 动画的速度具备“等级”关系。
  • CAAnimation不是唯一一个实现了CAMediaTiming的类。

速度的“等级关系”

如果一个动画组(Animation Group)的speed为2,而其中一个动画的speed为1.5,那么该动画将会以三倍的速度播放。

CAMediaTiming的其他应用

CAMediaTiming不仅被CAAnimation类实现,也同样被CALayer实现。后者是所有核心动画图层的基类。因此,对CALayer的speed赋值将会影响其上面添加的所有动画。最终speed = layer.speed * animation.speed。

动画暂停

通过设置speed属性为0,我们可以暂停一个动画。timeOffset属性为我们提供了一个可以从外部控制动画进程的机制。例如,可以通过slider来查看动画的每一个时刻的样子。
timeOffset属性乍一看会很奇怪。顾名思义,该属性用于抵消计算动画状态的时间。我们最好通过图画来解释。下图表示一个duration=3,timeOffset=1的动画。

图9.png

该动画直接调到“橙色->蓝色”这个动画过程的第1秒处开始执行(此时它已经不是纯橙色了——译者注),直到2秒时完全变为蓝色。随后,动画跳转到其纯橙色然后执行其第0秒第1秒的动画过程。也就是说,timeOffset将动画01秒的过程抽取了出来,放到最后执行。
这个属性本身没什么用处,但如果同时把speed设置为0,我们就可以控制动画的“当前状态”。被暂停的动画将会卡在第一帧上,如果你看上图所示的带偏移量的动画最开始的颜色,你会发现它其实是颜色变化开始1秒后应该呈现的颜色。通过将timeOffset设置为其他值,你可以看到动画该时刻的样子。

控制动画时序

speed和timeOffset结合使用可以控制动画的“当前”时间。如下所示是一个slider的实例,我们通过设置其timeOffset来查看方块的颜色变化。

Slider

这个例子非常简单,创建一个basic animation,加载到一个layer上。我们把动画的speed设置为0,让它停下。

CABasicAnimation *changeColor =
   [CABasicAnimation animationWithKeyPath:@"backgroundColor"];
changeColor.fromValue = (id)[UIColor orangeColor].CGColor;
changeColor.toValue   = (id)[UIColor blueColor].CGColor;
changeColor.duration  = 1.0; // For convenience

[self.myLayer addAnimation:changeColor
                   forKey:@"Change color"];
    
self.myLayer.speed = 0.0; // Pause the animation

然后在action方法中我们将slider的value赋值给做动画的layer的timeOffset属性:

- (IBAction)sliderChanged:(UISlider *)sender {
    self.myLayer.timeOffset = sender.value; // Update "current time"
}

效果图:

动图.gif

小结

  1. 通过设置fillMode为forward,并将removedOnCompletion设为NO,可以让图层保持在动画结束以后的状态。但是注意,animation对象只会影响到图层的PresentationLayer,而对ModelLayer没有影响。
  2. 如果对speed属性赋负值,动画会倒着执行。

私货

关于timeOffset

苹果官方文档的解释:

Specifies an additional time offset in active local time.
翻译过来就是“在本地活跃时间中指定一个额外的时间偏移量”。

听起来还是很费解是吧?其实timeOffset就是说,把动画时序中开头的某个时间段分割出来,“拼接”到动画的末尾。由于这个操作改变了动画真正的起点,因此,动画看起来就从分割处开始执行了。

animation的插值法

对于动画的“值”,苹果给出了三个属性,分别是fromValue, toValue, byValue。苹果规定,最多可以同时给这三个属性中的两个赋值。运行时,动画在“初始值”和“最终值”之间进行插值,从而确定各个时刻Layer的状态。初始值不一定是fromValue哦!
插值策略如下:

  • 赋值给fromValue和toValue:在fromValue、toValue之间插值。
  • 赋值给fromValue和byValue:在fromValue、fromValue + byValue之间插值。
  • 赋值给B和toValue:在toValue-byValue、toValue之间插值。
  • 赋值给fromValue:在fromValue和该属性当前的value之间插值。
  • 赋值给toValue:在keypath属性的presentationlayer的当前值和toValue之间插值。
  • 赋值给byValue:在keypath属性的presentationlayer的当前值和byValue之间插值。
  • 所有的都为nil:在keypath属性的presentationlayer先前的值和现在的值之间插值。

对于最后一条,我自己也没有尝试成功过。不知是不是个人理解出了偏差。这里先附上官文原文:

All properties are nil. Interpolates between the previous value of keyPath in the target layer’s presentation layer and the current value of keyPath in the target layer’s presentation layer.

欢迎各位大神指点!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容

  • 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥ios动画全貌。在这里你可以看...
    每天刷两次牙阅读 8,461评论 6 30
  • 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥iOS动画全貌。在这里你可以看...
    F麦子阅读 5,092评论 5 13
  • 先看看CAAnimation动画的继承结构 CAAnimation{ CAPropertyAnimation { ...
    时间不会倒着走阅读 1,635评论 0 1
  • 1. 简介 Core Animation 中文翻译为核心动画,它是一组非常强大的动画处理API,使用它能做出非常炫...
    lltree阅读 631评论 2 6
  • 介绍 : JLRoutes是一个调用极少代码 , 可以很方便的处理不同URL schemes以及解析它们的参数,并...
    CoderLF阅读 1,625评论 0 3