public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
public LinearInterpolator() {
}
public LinearInterpolator(Context context, AttributeSet attrs) {
}
public float getInterpolation(float input) {
return input; //这里直接返回了input跟我们的预期一致。
}
/** @hide */
@Override
public long createNativeInterpolator() {
return NativeInterpolatorFactoryHelper.createLinearInterpolator();
}
}
既然这是一个数学函数的关系,我们就可以利用坐标系来展示一下这种情况,利用坐标系也方便我们对其他的加速,减速甚至更复杂的加减速混合反向运动给出说明,
并给出这些对应运动的函数表达式
我们还是从最简单的开始画起,线性情况。很明显,这种情况上过小学的都会画。。。。。
这幅图最重要是反映速度的变化率,同样小学知识告诉我们关于s(t) 的公式关于t求导可以得出速度的随时间的变化规律即 v = 1
所以我们可以对速度变化公式v(t)求积分(这个小学恐怕不行。。。),来得到我们最终需要的s(t)的公式。
接下来我们就来试一下。。。加速运动:v会随时间增大,例如:v = t
那么求积分得到的s(t) = 1/2 t^2,你会发现不对,
因为时间到达1的时候距离没有到达1。。。。。所以这里的v和t的关系,是不能乱写的, 加速的表达方式是速度变化率,只要v和t是正相关就可以,
最终的结果我们需要利用s(t)的公式来保证,当t=0的时候,s要等于0;当t=1的时候,s也需要等于1,所以这里最后的
getInterpolator(float input){ return t^2 } 就会返回一个加速的插值器。
减速就是速度与时间负相关, v = -t ,同样的你会得到是s(t) = -(1/2)t^2,这他喵的一样有问题,那么-kt的k的系数要怎么去算出一个合理的k值呢,
我不得不祭出我的小学知识的最终奥义----------方程组(⊙﹏⊙)b来解决这一难题。
v = a - kt
注意这里我们考虑的是正向运动,所以v要有初值a
s(t) = at - 1/2kt^2
带入0。。。甭带了。。。都没了。。。
带入1 a - 1/2k = 1 所以大招得出的是符合条件的ak关系,a = 1/2k + 1 ,注意这里k必须为正值,(若为负值,其实就是加速运动了。。。)
我们随便带入一组数字。。。k=2,a=2,注意这里的k其实就是加速度绝对值,我们需要的加速度越大,把k变大就好了~
即s(t) = 2t - t^2(getInterpolator(float input){ return 2t - t^2 })
说完自己理解的减速插值器,看看android sdk里的DecelerateInterpolator是不是和我们的不谋而合呢
public float getInterpolation(float input) {
float result;
if (mFactor == 1.0f) {
result = (float)(1.0f - (1.0f - input) * (1.0f - input));
} else {
result = (float)(1.0f - Math.pow((1.0f - input), 2 * mFactor));
}
return result;
}
private float mFactor = 1.0f;
。。。我擦嘞,这哪里一样,要翻车呀三塞。。。
不要慌,让我们来仔细分析一下他的是怎么个意思,看看我们的s(t) = 2t - t^2能否自圆其说。如果不傻的同学,算一下第一个if中mFactor等于1的情况,
会发现结果是一样的,它提供了接口可以让我们设置mFactor的值,那我们看看mFactor不等于1的情况会怎样。
s(t) = 1 - (1-t)^(2*mFactor)
我输了。。。他这一手果然技高一筹(虽然我们的办法low了一些,但是达到效果是没问题的)
那我们举一反三一下就该知道,android自带的AccelerateInterpolator是怎么回事了, S(t) = t^(mDoubleFactor)
(这里有一个疑惑,Decelerate中的mFactor是一个float型,Accelerate中的mDoubleFactor = 2 * mFactor,但是声明DoubleFactor时是一个都double,
不知道这个脱裤子放屁的行为是要闹那样,当然何必在意这些细节,可能是三塞多虑了)
再看一个先减速后加速的例子吧,同样的我们自己先来抛砖(凭什么我就得是砖。对,不许糟践砖。。。)引玉一把,然后再对照Google大大们的做法自惭形秽一次。
先加速后减速会存在两种情况
(1)在某一段时间内加速,某一段时间内减速
(2)在某一距离内加速,某一段距离内减速 (这个我们用估值器以后用Evaluator来做)
(1)时间加减速情况:
我们传入一个变量标识时间百分比,这个好像直接传给我们了。。。,那我们就对fraction进行一个判断,比如说实现一个 fraction <= 0.5 减速 fraction > 0.5加速(为了减少脑细胞的坏死,我们就都拿一次幂来解释)
前半段:速度规律:a + kt
后半段:速度规律:(a + k/2) - kt (k绝对值相等是为了展现力的对称之美,这里面也有力与美的完美集合)
出来吧方程组!!!
s(t) = at + 1/2kt^2 t<0.5
s(t) = at + 1/2kt - 1/2kt^2 t>=0.5
1 = a + 1/2k - 1/2k
通过计算我们得出一种情况,即k可以为任意值,a必须等于1
我们尝试k=2带入
s(t) = t + t^2 t<0.5
s(t) = 2t - t^2 t<=0.5
我们尝试如果枢轴t不是0.5,可以是[0,1]范围内的任意值的方程又会是怎样呢,我们假设枢轴为Z
s(t) = at + 1/2kt^2 t<Z
s(t) = at + 1/2*Zkt - 1/2kt^2 t>=Z
1 = a + 1/2*Zk - 1/2kt 这种情况下 k就会和Z、a相关
class AcDcInterpolater(val timePivot: Float, val accelebration: Float) : Interpolator {
val factor: Float = 1 - 1 / 2.0f * timePivot * accelebration + 1 / 2.0f * accelebration
override fun getInterpolation(fraction: Float): Float {
when (fraction.compareTo(timePivot)) {
-1 ->
return (factor * fraction + 1 / 2f * accelebration * Math.pow(fraction.toDouble(), 2.0)).toFloat()
else ->
return (factor * fraction + 1 / 2f * timePivot * accelebration - 1 / 2f * accelebration * Math.pow(fraction.toDouble(), 2.0)).toFloat()
}
}
}
上面的代码存在的问题是会导致反向运动,当使用了不合适的参数时。
那看看google大大们的怎么搞
public class AccelerateDecelerateInterpolator extends BaseInterpolator
implements NativeInterpolatorFactory {
public float getInterpolation(float input) {
return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}
当我们沉浸在利用小学数学解题的快乐中无法自拔的时候,Google大大们已经开始玩儿起啦高中数学。。。。
就先到这里吧。。。总之,心态已崩