iOS动画自定义时间函数
动画基础
动画在UI交互中是一种增强用户体验的利器,现在几乎每一个移动App都会使用到各种动画效果。苹果Cocoa框架对动画效果的支持非常强大,为开发者提供了丰富的Api实现各类动画效果。
iOS开发中实现动画效果通常有三种方式。
- 基于
CALayer
的Core Animation
框架,这是动画的基础框架。 - 基于
UIView
,为了方便实现简单的动画封装的UIView Animation
。 - 在游戏开发中经常用到的基于物理模拟的动画框架
UIKit Dynamics
。
核心动画
Core Animation
正如其名,是所有动画的核心实现。它可以满足我们对动画的所有要求。
可能最常见的情况是将一个 view 的属性从一个值改变为另一个值,比如
let animationX = CABasicAnimation()
animationY.keyPath = "position.x"
animationY.fromValue = 0
animationY.byValue = 300
animationY.duration = 2.0
animationX.timingFunction = CAMediaTimingFunction(name:kCAMediaTimingFunctionLinear)
rect-linear.gif
这段代码表示一个在x方向上从0线型移动到300,耗时2秒的动画。可以看到
Core Animation
提供的API非常简洁,很容易理解。
时间函数
可以看到,上面的方块是线型移动的,这是因为我们设置了其动画的时间函数为CAMediaTimingFunction(name:kCAMediaTimingFunctionLinear)
。时间函数通过修改持续时间的分数来控制动画的速度。
Core Animation
提供两种方式创建时间函数,一种是预定义的命名时间函数:CAMediaTimingFunction(name:String)
-
淡入 (kCAMediaTimingFunctionEaseIn):
-
淡出 (kCAMediaTimingFunctionEaseOut):
-
淡入淡出 (kCAMediaTimingFunctionEaseInEaseOut):
- 默认 (kCAMediaTimingFunctionDefault):
另一种是通过传入两个控制点创建贝塞尔曲线(cubic Bézier)函数:
CAMediaTimingFunction(c1x:Float,c1y:Float,c2x:Float,c2y:Float)
关于贝塞尔曲线的细节这里不展开讨论,有兴趣的看官们可以移步cubic-bezier.com,这个网站可以直接看到通过控制点创建的贝塞尔曲线的函数图像,awesome!
自定义时间函数
Core Animation
只提供了有限的时间函数,能满足我们大部分的需求。但是如果我们要实现类似下图的效果,方块按照Sin正弦函数的方式进行动画,应该怎么做呢?
为此我写了一个微型的库——
TFAnimation
,接收一个自定义的时间函数,是一个(CGFloat) -> CGFloat
类型的闭包,其定义域为[0,1]。比如,线型时间函数可以定义如下。
let animationY = TFBasicAnimation()
//指定其他的属性,就像CABasicAnimation
animationY.keyPath = "position.y"
animationY.fromValue = 0
animationY.byValue = height / 4
animationY.duration = 5.0
animationY.additive = true
animationY.timeFunction = { $0 }
所以,实现上图的效果,其实就是在x方向上时间函数是平移,在y方向上,时间函数是正弦函数
animationY.timeFunction = { -CGFloat(sin(4.0 * M_PI * Double($0)) }
其实实现的原理也很简单,代码量也不多,核心思想是继承CAKeyframeAnimation
,把通过时间函数计算出相应的帧位置,填充到CAKeyframeAnimation.values
中。具体的实现我放在了github上,TFAnimation,直接运行就是上图的正弦动画,走过路过的小伙伴随手点个Star呗!有任何意见建议的小伙伴欢迎评论留言~