简析缓动曲线
Introduce of the EaseCurve
前言
动效是用户体验很重要的一部分。随着设备性能提升和人们对于用户体验越来越高的追求,动效将会越来越重要。动效要遵循客观物理规律以及人的视觉经验,符合用户预期,让用户感觉自然,才能获得用户的喜爱。
本文将从为什么探究缓动曲线、利用物理公式探究缓动曲线、常用缓动曲线、使用曲线拟合尝试剖析苹果ScrollView动效参数、使用线性插值高仿APP动效进行介绍。希望阅读后,本文能给你在制作动效时带来一点帮助。
为什么探究缓动曲线
动画是源自现实世界的,人类早已习惯了一个变速运动的物理环境,一个简单的匀速动画会让人相对感觉不适。所以需要让我们的动效符合物理规律。缓动曲线表述动画变化的程度与时间的关系,常用于模拟物理世界中一些常见动作。而从动画体验来说,不同的缓动曲线会带给用户不同体验。一般为:匀速运动 < 变速运动 < 物理缓动。
苹果官方的UIView提供了Linear,EaseIn,EaseOut,EaseInout还有bezier动画函数,然而只是局限于使用,知其然而不知其所以然。例如用ease-in来做小球从高处掉下的效果,这个加速效果没有遵循相关物理原理,使得出来的动画效果不太自然。
利用物理公式探究缓动曲线
以下以弹簧动画为例,探究一下怎样模拟出这个效果。
ios9提供了CASpringAnimation类实现该效果,而web上就没有提供类似函数。但我们仍然可以通过以前学过的物理学和数学知识来做一下研究。
下面有一个弹簧块,假设它质量为1,在它不动的时候位置是x = 1,则拉伸时的距离就是x-1了:
将这比作一个动画,弹簧块在时间t时所处的位置x就可以看作动画曲线函数x = f(t)。如果我们求得这个函数公式,就可以模拟出这个动画效果了。对此,下图将通过物理学公式和数学知识进行探讨。
在 Wolfram | Alpha中输入以上公式后得出
使用工具绘制函数得:
感觉还是蛮像一个弹簧曲线的运动轨迹的嘛。像这样,如果我们要模仿自然生活中的某个运动轨迹,可以如上探究一下背后的物理方程,运用数学知识计算,和使用合适的工具,来模拟出对应的运动曲线。但估计很多人都把这些知识还给老师了,因此如果所有曲线都要自己探究的话,就真是太难了。
不要担心,后面还有一大半的篇幅,就是帮你解决这个问题的。
常用缓动曲线
下面是常见的缓动曲线(tween算法),我们下面将给出对应曲线的函数公式和代码,cubic-bezier这个网站还提供了对应贝塞尔参数。
EaseIn是从慢到快的曲线,就像开车时先慢后快,EaseOut和EaseIn的曲线图像关于(0.5,0.5)中心对称,EaseInOut:分别由EaseIn、EaseOut分别缩小一半,然后再拼接一起
Quad,Cubic,Quart ,Quint:幂函数二次到五次曲线
// Modeled after the parabola y = x^2
double fsQuadraticEaseIn(double p)
{
return p * p;
}
// Modeled after the parabola y = -x^2 + 2x
double fsQuadraticEaseOut(double p)
{
return -(p * (p - 2));
}
// Modeled after the piecewise quadratic
// y = (1/2)((2x)^2) ; [0, 0.5)
// y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1]
double fsQuadraticEaseInOut(double p)
{
if(p < 0.5){
return 2 * p * p;
}else{
return (-2 * p * p) + (4 * p) - 1;
}
}
// Modeled after the cubic y = x^3
double fsCubicEaseIn(double p)
{
return p * p * p;
}
// Modeled after the cubic y = (x - 1)^3 + 1
double fsCubicEaseOut(double p)
{
double f = (p - 1);
return f * f * f + 1;
}
// Modeled after the piecewise cubic
// y = (1/2)((2x)^3) ; [0, 0.5)
// y = (1/2)((2x-2)^3 + 2) ; [0.5, 1]
double fsCubicEaseInOut(double p)
{
if(p < 0.5){
return 4 * p * p * p;
}else{
double f = ((2 * p) - 2);
return 0.5 * f * f * f + 1;
}
}
// Modeled after the quartic x^4
double fsQuarticEaseIn(double p)
{
return p * p * p * p;
}
// Modeled after the quartic y = 1 - (x - 1)^4
double fsQuarticEaseOut(double p)
{
double f = (p - 1);
return f * f * f * (1 - p) + 1;
}
// Modeled after the piecewise quartic
// y = (1/2)((2x)^4) ; [0, 0.5)
// y = -(1/2)((2x-2)^4 - 2) ; [0.5, 1]
double fsQuarticEaseInOut(double p)
{
if(p < 0.5){
return 8 * p * p * p * p;
}else{
double f = (p - 1);
return -8 * f * f * f * f + 1;
}
}
// Modeled after the quintic y = x^5
double fsQuinticEaseIn(double p)
{
return p * p * p * p * p;
}
// Modeled after the quintic y = (x - 1)^5 + 1
double fsQuinticEaseOut(double p)
{
double f = (p - 1);
return f * f * f * f * f + 1;
}
// Modeled after the piecewise quintic
// y = (1/2)((2x)^5) ; [0, 0.5)
// y = (1/2)((2x-2)^5 + 2) ; [0.5, 1]
double fsQuinticEaseInOut(double p)
{
if(p < 0.5){
return 16 * p * p * p * p * p;
}else{
double f = ((2 * p) - 2);
return