interpolator, typeEvaluator 以及属性动画的参数

先下我的结论。它们都是对动画的控制。
interpolator 插值器:时间和进度(百分比)的关系函数
typeEvaluator  估值器:进度(百分比)和具体进度数据的关系函数
属性动画的参数:指定了属性的初始值和结束值。由于默认有interpolator 和 系数为1的线性typeEvaluator。所以我们才会看到一般的动画是开始和结束慢,中间匀速。


想象一下,如果我们把参数设置的足够多。比如一个5秒动画,设置了120个进度数据。相当于1秒24个进度数据,人眼是看不出来任何停顿的。
那么我们就不需要设置interpolator和typeEvaluator了。因为函数是虽然是连续的。但是人眼的视觉不是连续的。所以我们不需要连续的函数。只需要足够多的点。
因为我们设置了120个进度数据,那么app会每过 1/24 秒 ,进入下一个进度。人眼感知的进度已经到达极限。所以我们不需要interpolator。相当于拼凑出来一个进度函数。
又由于我们是直接设置了进度数据,不需要进度和进度数据的转换,就算是用默认的系数为1的线性转换,也没有任何关系,
因为人眼的视觉不是连续的,人眼看不到2帧之间的变化太大的内容。
所以,控制进度用interpolator。

进度和进度数据需要修正用typeEvaluator。

实在太复杂的函数,那么直接死办法,

 

跟据动画时间把参数做到足够多(秒数*24),就可以ignor2个函数。

如果没有这么精力求出参数,那么也必须注意参数的个数设置不是根据关键点的数量来设置,

参数与参数之间代表的是2个参数度过的时间是相等的。
如果动画的1/2处和1/3处。必须标注出来值。那么必须取2和3的公倍数6.就是说最少要6个参数。或者6的倍数的动画才会比较精确。

 


下面的内容会用一个汽车的例子来说明interpolator 、typeEvaluator的用处。
用一个匀速的汽车引出interpolator。再用汽车沿路返回引出typeEvaluator.(用颜色的转变更可以说明此函数的必要,颜色的变化和进度值没办法直接线性挂钩)
举一个最常见的动画:汽车从控件左边开到控件右边。共500px
汽车发动,匀速行驶,缓慢停止。
很容易感知汽车速度由慢变快变慢,到停止。
对于属性动画来说。我们要控制的就是图片的transferbyX.
我们一般会给出初始和结束的x轴的距离参数:0和500和动画时间:假如5000; 动画就会动了。如代码1.
假如屏幕1秒刷新10次,app是如何知道0.1秒汽车该放到哪里呢?我们并没有给出0.1秒的值。我们只给了0和5的值。
因为ValueAnimator默认设置了:private static final TimeInterpolator sDefaultInterpolator = new AccelerateDecelerateInterpolator();

如果我们想要控制改变动画进度。比如进度不是一个2头慢的模型。而是一个匀速的呢?那么必须自定义interpolator.内插器。相当于进度条控制器的意思。见代码2.

这里我们模拟给出几个时间点的进度和进度具体值数据:

时间 进度
0 0 0
1 0.16 0.2
2 0.32 0.4
3 0.6 0.6
4 0.84 0.8
5 1 1

事件 移动距离
0 0px 0px
1 80px 100px
2 180px 200px
3 300px 300px
4 420px 400px
5 500px 500px

interpolator就是控制进度数据的。
这样知道了进度如.0.2,我们用500*0.2就知道该移动100px了。
如此,好像不再需要其他控制了。typeEvaluator根本不需要设计出来。
确实,在这个前进的例子中确实没有任何必要typeEvaluator了。
但是假如我们的动画是一个匀速前进300px .再匀速后退200px的动画呢?
当然可以分成2个动画来做。但是其实本质上应该是一个动画的。因为只有一个属性。
这里就是一个进度和进度表示的数据不是线性关系的问题。
我们已经有了时间和进度的关系函数:interpolator。
我们还需要一个进度和进度数据的关系函数typeEvaluator
默认的interpolator和 typeEvaluator 见代码3.


代码1:
@Override
protected void onAttachedToWindow()
{
super.onAttachedToWindow();
valueAnimator=ValueAnimator.ofFloat(0,300);
valueAnimator.setDuration(5000);

valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
float moveX=(Float) animation.getAnimatedValue();
mMovex=moveX;
invalidate();
}
});

下面的内容会用一个汽车的例子来说明interpolator 、typeEvaluator的用处。
用一个匀速的汽车引出interpolator。再用汽车返回行驶引出typeEvaluator.
举一个最常见的动画:汽车从控件左边开到控件右边。共500px
汽车发动,匀速行驶,缓慢停止。
很容易感知汽车速度由慢变快变慢,到停止。
对于属性动画来说。我们要控制的就是图片的transferbyX.
我们一般会给出初始和结束的x轴的距离参数:0和500和动画时间:假如5000; 动画就会动了。如代码1.
假如屏幕1秒刷新10次,app是如何知道0.1秒汽车该放到哪里呢?我们并没有给出0.1秒的值。我们只给了0和5的值。
因为ValueAnimator默认设置了:private static final TimeInterpolator sDefaultInterpolator = new AccelerateDecelerateInterpolator();

如果我们想要控制改变动画进度。比如进度不是一个2头慢的模型。而是一个匀速的呢?那么必须自定义interpolator.内插器。相当于进度条控制器的意思。见代码2.

这里我们模拟给出几个时间点的进度和进度具体值数据:

时间 进度
0 0 0
1 0.16 0.2
2 0.32 0.4
3 0.6 0.6
4 0.84 0.8
5 1 1

事件 移动距离
0 0px 0px
1 80px 100px
2 180px 200px
3 300px 300px
4 420px 400px
5 500px 500px

interpolator就是控制进度数据的。
这样知道了进度如.0.2,我们用500*0.2就知道该移动100px了。
如此,好像不再需要其他控制了。typeEvaluator根本不需要设计出来。
确实,在这个前进的例子中确实没有任何必要typeEvaluator了。
但是假如我们的动画是一个匀速前进400px .再匀速后退100px的动画呢?
当然可以分成2个动画来做。但是其实本质上应该是一个动画的。因为只有一个属性。
这里就是一个进度和进度表示的数据不是正系数为1的线性关系的问题。
我们已经有了时间和进度的关系函数:interpolator。
我们还需要一个进度和进度数据的关系函数typeEvaluator,来实现返回效果。见代码4.


ps:默认的interpolator和 typeEvaluator 见代码3.

代码1:
@Override
protected void onAttachedToWindow()
{
super.onAttachedToWindow();
valueAnimator=ValueAnimator.ofFloat(0,300);
valueAnimator.setDuration(5000);

valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
float moveX=(Float) animation.getAnimatedValue();
mMovex=moveX;
invalidate();
}
});
valueAnimator.start();
}


代码2
public static class FixSpeed implements Interpolator
{
@Override
public float getInterpolation(float input)
{
return input;
}
}

valueAnimator.setInterpolator(new FixSpeed());

 


代码3
private TimeInterpolator mInterpolator = sDefaultInterpolator;
public class AccelerateDecelerateInterpolator extends BaseInterpolator implements NativeInterpolatorFactory
{
public float getInterpolation(float input) {
return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}
}


private static final TypeEvaluator sFloatEvaluator = new FloatEvaluator();

public class FloatEvaluator implements TypeEvaluator<Number> {
public Float evaluate(float fraction, Number startValue, Number endValue) {
float startFloat = startValue.floatValue();
return startFloat + fraction * (endValue.floatValue() - startFloat);
}
}

 

代码4
public static class BackEvaluater implements TypeEvaluator<Float>
{
@Override
public Float evaluate(float fraction, Float startValue, Float endValue)
{
if(fraction<=0.8)
{
return startValue+(endValue-startValue)*fraction;
}
else
{
float realfraction=0.8f-(fraction-0.8f);
return startValue+(endValue-startValue)*realfraction;
}
}
}

posted @ 2019-12-07 11:26  琴鸟  阅读(289)  评论(0编辑  收藏  举报