模仿Skype上滑菜单动画

409 查看

最近维持着平时学语言底层,周末做动效的学习节奏。学习到了很多。在制作动效的时候,尤其是在写贝塞尔曲线的代码,自己都会用纸笔计算坐标以及绘出大致的图形,是一个很有趣的过程。

这次的作品是受到skype的启发。在skype的iOS版本app中,点击照相按钮,会出现上滑菜单。查看效果的地址可以点这里。这是类似于一种多弹簧的一个组合。

分析并拆解动画

视图拆解

我们可以把这个动画的整体View拆解成两个部分组成,菜单顶端的边缘部分Type1、Type3和中央部分Type2。其中,Type2是作为贝塞尔曲线的control点,而Type1和Type3是定点。而且在RectView的上半部分,还要加入一处空白的位置来作为贝塞尔图形的上下文。

动画拆解

其实在进行过视图拆解后,动画拆解就十分容易了。全动效是模仿着不同压力成都下的三个弹簧,而且,它们的顶点始终是一条贝塞尔曲线。而弯曲程度和弯曲方向只由control点来控制。通过观察官方效果图,control点是一个连续性上下平移的店,所以我们只需要给出一个先增后减,再增减(重复这个弹簧过程,每次转向会有峰值衰减),直到最终结果为0时,就停止运动,即Type1、Type2、Type3三个顶点在水平方向为一条直线。

21

22

利用UIView的drawRect:函数来刷新图形

在动效执行时候,往往是每经历一个不同的手势状态,就要重新绘制贝塞尔图形。在之前的QQ Message Bubble’s Copy – DGSlimeView中,通过panHeadDot: (UIPanGestureRecognizer *)回调函数,在UIGestureRecognizerStateChanged状态下我们可以实现这种效果。但是这里并不需要手势而不断更新。这里我们使用CADisplayLink来实现界面重绘。而在我们使用该函数之前,我们要了解一些关于UIView的知识,关于drawRect:在什么情况下会自动调用:

  • 若在UIView初始化时没有设置Rect大小,将导致drawRect:不被自动调用。drawRect调用时在loadViewviewDidLoad两方法之后。
  • 该方法在调用sizeToFit后会被自动调用。
  • 通过设置contentMode属性值为UIViewContentModeRedraw,将在每次设置或更高frame的时候自动调用。
  • 直接调用setNeedsDisplay或者setNeedsDisplayInRect后将会触发drawRect,前提是该ViewRect不能为0.

在重构界面的最后,我们了解一下CADisplayLink。简单地理解,CADisplayLink就是一个定时器,每隔秒(约16.667ms)刷新一次。使用的时候,我们要把它添加到一个runloop中,并给他绑定targetSEL,在SEL的函数对象中,我们重新计算我们需要的数值,再根据drawRect自动调用的性质,主动调用函数setNeedsDisplay也就完成了界面的刷新。

对于该示例,我们给出刷新的代码:

计算弹性数组序列

先要确定我们的目标:构造一个连续序列,这个序列的末状态是0,过程中先增大,再减小,再增大……重复以上过程,因为阻尼衰减,到最后会停留在0,则序列结束。这个连续序列就好比缓动函数中的EaseOutElastic

在iOS7之后,Apple在UIView Class Refference增加了弹簧动画效果。

我们的灵感来自于官方的这个函数。这里在构造序列的时候,通过两个视图在不同的时间内执行弹簧动画,即可得到我们所需要的序列(文字说的不明白,可以看我录制图)。这种方法在Kitten-Yang的书中第二章也详细的介绍了,被称作辅助视图(Side Helper View)法。这里我把效果放慢,大家观察两个不同颜色的Rect在Y轴上的距离变化:

这里输出的序列数据也就是上面代码中的diff,这时候在回头看之前的代码是否都明确了?想想其实也很容易的^_^。这时候我们只要以计算出的序列数值来改变贝塞尔曲线的control点,每次绘制一遍贝塞尔图形即可,我们通过重写drawRect来实现。上代码:

收尾工作

以上介绍了这个动效的全部思路,最后的工作就是对runloop进行释放。这里我先贴出代码:

留意Notice部分。这种做法的原因如果大家写过C那就一定很清楚,在调用invalidate之后,知识进行了内存空间的释放(相当于C中的free),指针此时会指向一个无效对象,通常称之为悬挂指针(Dangling Pointer),所以我们通过将指针指向nil,使之彻底清空,防止crash。如果大家想深入理解,可以翻看Effective Objective-C 2.0一书的Item 29: Understand Reference Counting

43524534

写在最后

意思文中只是讲解了核心的思想和代码,建议大家去访问我的github仓库下载代码,结合代码理解思路。喜欢的话,大家也可以来个star。


Github【Desgard_Duan】

A Guide To iOS Animation 2.0 · 2.玩转贝塞尔曲线【Kitten-Yang】

Effective Objective-C 2.0 · Understand Reference Counting【Matt Galloway 】