iOS UIView动画实践(五):Keyframe Animation

前言

有些时候你们可能会遇到制做复杂、具备连贯性UIView动画的需求,这时你们可能会使用在completion闭包中衔接一段一段的动画,使之成为一段连续的动画。闭包

若是咱们只是链接2个,或者3个动画,这种方式或许还行得通,但若是有更多的动画片断须要链接的时候,这种方式会带来灾难性的问题,你的代码会很是的冗余,不断的在completion闭包中嵌套代码,使代码维护起来至关的困难。因此今天向你们介绍能更好地实现这个需求的方法,Keyframe动画。app

Keyframe动画可让咱们有效的拆分由若干段动画链接而成的复杂动画,能够较为精准的定义每段动画的起始点及持续时间,而且在代码组织方面也很是清晰。先看看今天要带你们实现的动画Demo:动画

           

使用场景

咱们先来认识一下,在什么样的场景下须要使用Keyframe动画。如图下所示,这是一个由四段动画组成的一个复杂动画,让UIView沿着长方形的轨迹运动:spa

咱们来看看用代码如何实现:.net

[cpp] view plaincopyrest

  1. UIView.animateWithDuration(1, animations: {  code

  2.     view.center.x += 200.0  orm

  3. }, completion: { _ in  ip

  4.     UIView.animateWithDuration(1, animations: {  文档

  5.         view.center.y += 100.0  

  6.     }, completion: { _ in  

  7.         UIView.animateWithDuration(1, animations: {  

  8.             view.center.x -= 200.0  

  9.         }, completion: { _ in  

  10.             UIView.animateWithDuration(1, animations: {  

  11.                 view.center.y -= 100.0  

  12.             }, completion: nil)  

  13.         })  

  14.     })  

  15. })  

经过上面的伪代码能够看到,咱们使用了completion闭包的方式链接每一段的动画,代码看起来尚且算清晰,可读性也马马虎虎。可是你们想象一下,若是咱们使UIView按照一个复杂的路线运行,这一段动画可能有十几、几十段动画组成的,那么若是再使用completion闭包这种方式链接,那代码是多么的惨不忍睹。幸亏咱们有Keyframe动画,下面就让咱们来看看如何使用Keyframe动画。

Keyframe动画

首先咱们会使用到UIView的另外一个动画方法animateKeyframesWithDuration(_: delay: options: animations: completion: ) 

[cpp] view plaincopy

  1. UIView.animateKeyframesWithDuration(2, delay: 0, options: [], animations: {  

  2.     // add keyframes  

  3. }, completion: nil)  

这个方法的几个参数与前几个使用过的动画方法参数同样。上面代码片断的意思是整个关键帧动画的持续时间为2秒、无延迟、无动画选项、执行完毕后无后续执行的代码。

注:该方法的动画选项再也不是UIViewAnimationOptions,而是UIViewKeyframeAnimationOptions。具体的内容你们能够去查阅Apple的文档。

接下来咱们要在animations闭包中添加关键帧了:

[cpp] view plaincopy

  1. UIView.animateKeyframesWithDuration(2, delay: 0, options: [], animations: {  

  2.     UIView.addKeyframeWithRelativeStartTime(0, relativeDuration: 0.25, animations: {  

  3.         view.center.x += 200.0  

  4.     })  

  5. }, completion: nil)  

addKeyframeWithRelativeStartTime(_: relativeDuration: animations: )是UIView添加关键帧的方法,该方法有三个参数:

  • startTime:关键帧开始时间,该时间是相对整个关键帧动画持续时间的相对时间,通常值在0到1之间。若是为0,则代表这一关键帧从整个动画的第0秒开始执行,若是设为0.5,则代表从整个动画的中间开始执行。

  • relativeDuration:关键帧持续时间,该时间一样是相对整个关键帧动画持续时间的相对时间,通常值也在0到1之间。若是设为0.25,则代表这一关键帧的持续时间为整个动画持续时间的四分之一。

  • animations:设置视图动画属性的动画闭包。

咱们解释一下上面这段代码。整个关键帧动画的持续时间为2秒,第一个关键帧从第0秒开始,运行0.5秒结束。下面咱们完成其余三个关键帧:

[cpp] view plaincopy

  1. UIView.animateKeyframesWithDuration(2, delay: 0, options: [], animations: {  

  2.     UIView.addKeyframeWithRelativeStartTime(0, relativeDuration: 0.25, animations: {  

  3.         view.center.x += 200.0  

  4.     })  

  5.     UIView.addKeyframeWithRelativeStartTime(0.25, relativeDuration: 0.25, animations: {  

  6.         view.center.y += 100.0  

  7.     })  

  8.     UIView.addKeyframeWithRelativeStartTime(0.5, relativeDuration: 0.25, animations: {  

  9.         view.center.x -= 200.0  

  10.     })  

  11.     UIView.addKeyframeWithRelativeStartTime(0.75, relativeDuration: 0.25, animations: {  

  12.         view.center.y -= 100.0  

  13.     })  

  14. }, completion: nil)  

第二个关键帧的开始时间为0.25,也就是从整个动画时间的第0.5时开始执行,一样持续0.5秒。后两个关键帧的参数就不难理解了。

如今整个代码看起来很是整洁,条理清晰,可读性很是好,并且能够有更精确的控制。即便再多几个关键帧也一样能够从容应对。

关键帧动画不只仅用于同一个视图的分段动画,也可以使使用于不一样视图的组合动画,因为咱们还没讲到图层动画,因此,开篇的示例动画中就使用了关键帧动画实现了多个视图的组合动画。

示例动画

在这个示例中虽然看起来是一个纸飞机视图的连续动画,但实际上是由三个纸飞机视图组合而成的:

从图中能够看到实际上是有三个纸飞机视图,只不过在界面加载以前2号和3号纸飞机视图的透明度都是为零。

整个动画是由这三个纸飞机视图经过关键帧动画组合而成:

图中标示出了三个飞机视图的运行轨迹、视图大小、视图透明度的状态,咱们来看看代码如何实现:

[cpp] view plaincopy

  1. let zoomInScaleTransform = CGAffineTransformMakeScale(0.2, 0.2)  

  2. UIView.animateKeyframesWithDuration(3, delay: 0, options: [], animations: {  

  3.     UIView.addKeyframeWithRelativeStartTime(0, relativeDuration: 0.2, animations: {  

  4.         self.customHeaderView.paperAirplane.center.x += self.view.frame.width  

  5.         self.customHeaderView.paperAirplane.center.y += -180  

  6.         self.customHeaderView.paperAirplane.transform = zoomInScaleTransform  

  7.     })  

  8.     UIView.addKeyframeWithRelativeStartTime(0.3, relativeDuration: 0.01, animations: {  

  9.         self.customHeaderView.paperAirplaneOpposite.alpha = 1  

  10.         self.customHeaderView.paperAirplaneOpposite.transform = zoomInScaleTransform  

  11.     })  

  12.     UIView.addKeyframeWithRelativeStartTime(0.3, relativeDuration: 0.5, animations: {  

  13.         self.customHeaderView.paperAirplaneOpposite.transform = CGAffineTransformIdentity  

  14.         self.customHeaderView.paperAirplaneOpposite.center.x -= self.view.frame.width  

  15.         self.customHeaderView.paperAirplaneOpposite.center.y += 90  

  16.     })  

  17.     UIView.addKeyframeWithRelativeStartTime(0.9, relativeDuration: 0.01, animations: {  

  18.         self.customHeaderView.paperAirplaneComeBack.alpha = 1  

  19.     })  

  20.     UIView.addKeyframeWithRelativeStartTime(0.9, relativeDuration: 0.2, animations: {  

  21.         self.customHeaderView.paperAirplaneComeBack.center.x += 33  

  22.     })  

  23. }, completion: { _ in  

  24.     self.restorePaperAirplaneStatus()  

  25. })  

你们看到这你们可能会有疑问了,三段动画怎么会有五个关键帧呢,咱们来刨析一下:

  • 第一个关键帧:完成1号纸飞机视图运动到右上角并移出屏幕,视图逐渐变小的动画。该关键帧从整个动画的第0秒开始执行,持续时间为0.6秒。

  • 第二个关键帧:因为2号纸飞机视图的初始透明度为零,因此在第二个关键帧将透明度设为1,而且缩小视图。注意这两个动做须要在瞬间完成,因此relativeDuration设为0.01,一个极短的时间。开始时间为整个动画的第0.9秒开始,较第一个关键帧延迟0.3秒。

  • 第三个关键帧:与第二个关键帧同时开始执行,完成2号纸飞机视图从小变大、而且往左下角运动,一直移出屏幕。持续时间为1.5秒。

  • 第四个关键帧:与第二个关键帧做用类似,改变3号纸飞机视图的透明度,一样是在瞬间完成。

  • 第五个关键帧:与第四个关键帧同时执行, 完成向右移动的动画,持续0.6秒。

关键帧完成以后,在completion闭包中调用restorePaperAirplaneStatus()方法,恢复3个纸飞机视图的状态及位置,以便再次执行动画。

总结

你们在使用关键帧动画时,对于关键帧的开始时间和持续时间须要仔细设置,保证每一个关键帧在合适的时间开始,执行恰当的持续时间。在必要时候也须要在关键帧里修改视图的一些状态,但要设置极短的持续时间,表示瞬间完成。

下一篇会向你们介绍在使用Auto Layout的状况下,如何经过约束实现动画,好了今天就先到这里吧。

相关文章
相关标签/搜索