当数学遇上动画:讲述 ValueAnimator、TypeEvaluator和TimeInterpolator之间的恩恩怨怨(1)
其实关于 ValueAnimator
的内部工作原理大家也都清楚,本文只是选择从数学函数的角度来解析这个原理,方便理解。看完了本节之后我们就更加清楚如何借助 TypeEvaluator
和 TimeInterpolator
来帮助我们实现动画等知识。
本系列文章共有三篇,第一篇通过源码解析ValueAnimator
类,第二篇通过实例解析TimeInterpolator
和TypeEvaluator
,第三篇分析常见动画背后的缓动函数,最后引出一个新的Android动画开发的辅助库Yava。
1 Android动画基础知识
(1)狭义而言,动画一般就是指某个View组件的某个或者某些属性值在一段时间内不断变化的过程,这个变化过程往往有个起始值、结束值和一系列的中间值,ValueAnimator
就是用来反映这个属性值变化过程的重要类,所以本文的介绍主要是以分析ValueAnimator
为主。 (2)如果将属性值的变化过程看做一个数学函数的话,从动画效果上来看它是连续的,但实际上它还是离散的,因为它实际上也就是通过插入中间值(简称插值)从而”一帧一帧”完成动画的,那每一帧在哪里取,取多少呢?这也就是ValueAnimator
类主要完成的作用。
那到底ValueAnimator
是怎么控制属性值的变化过程的呢?答案是借助TimeInterpolator
和TypeEvaluator
来帮忙!TimeInterpolator
用来控制在哪里取,而TypeEvaluator
用来控制取多少。(注:取多少个点进行插值是不确定的,例如动画持续时间1s,可能取60,也可能取54、57或者58个中间点进行插值)
先说本小节结论,每一个ValueAnimator
其实就是一个的TimeInterpolator
和一个TypeEvaluator
的结合体。从数学的角度来看,ValueAnimator
就是由TimeInterpolator
和TypeEvaluator
这两个简单函数组合而成的一个复合函数。用图来表述如下:
你也可以将TimeInterpolator
和TypeEvaluator
看作是工厂流水线上的两个小员工,那么ValueAnimator
就是车间主管啦。TimeInterpolator
这个小员工面对的是产品的半成品,他负责控制半成品输出到下一个生产线的速度。而下一个生产线上的小员工TypeEvaluator
的任务就是打磨半成品得到成品,最后将成品输出。
2 结合源码解释函数形式
(1)假设TimeInterpolator
是函数x=f(t),t表示动画已经完成的时间比率(例如动画的总时长是10s,已经过了4s了,那么t=0.4),所以t的取值范围是[0,1],0表示动画开始,1表示动画结束。该函数的返回值指的是动画实际插值的时间点,一般是0到1之间,但是也可以小于0(”下冲”)或者大于1(”上冲”)。 该函数的作用是把当前时间进度映射成另一个值,这样动画参照的时间由此被”篡改”,动画的速度由此被改变。 (后面还有详细介绍)
参考接口TimeInterpolator
的定义:
1 2 3 4 5 6 7 8 9 10 11 12 |
/** * A time interpolator defines the rate of change of an animation. This allows animations * to have non-linear motion, such as acceleration and deceleration. */ public interface TimeInterpolator { /** * Maps a value representing the elapsed fraction of an animation to a value that represents * the interpolated fraction. This interpolated value is then multiplied by the change in * value of an animation to derive the animated value at the current elapsed animation time. */ float getInterpolation(float input); } |
(2)假设TypeEvaluator
是函数y=g(x,a,b),x就是前面函数f(t)篡改之后的插值的时间点,a、b分别表示属性动画的起始值和结束值。 该函数的作用是通过起始值、结束值以及插值时间点来计算在该时间点的属性值应该是多少。
参考接口TypeEvaluator
的定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/** * Interface for use with the {@ link ValueAnimator#setEvaluator(TypeEvaluator)} function. Evaluators * allow developers to create animations on arbitrary property types, by allowing them to supply * custom evaluators for types that are not automatically understood and used by the animation * system. */ public interface TypeEvaluator<T> { /** * This function returns the result of linearly interpolating the start and end values, with * <code>fraction</code> representing the proportion between the start and end values. The * calculation is a simple parametric calculation: <code>result = x0 + t * (x1 - x0)</code>, * where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>, * and <code>t</code> is <code>fraction</code>. */ public T evaluate(float fraction, T startValue, T endValue); } |
(3)假设TimeInterpolator
和TypeEvaluator
是上面两个简单函数,那么ValueAnimator
也是一个函数,它其实就是表示TimeInterpolator
的函数x=f(t)和表示TypeEvaluator
的函数y=g(x,a,b)结合而成的复合函数F=g(f(t),a,b)
。
参考ValueAnimator
中animateValue
方法的定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
/** * This method is called with the elapsed fraction of the animation during every * animation frame. This function turns the elapsed fraction into an interpolated fraction * and then into an animated value (from the evaluator. The function is called mostly during * animation updates, but it is also called when the <code>end()</code> * function is called, to set the final value on the property. */ void animateValue(float fraction) { fraction = mInterpolator.getInterpolation(fraction); //TimeInterpolator 函数 mCurrentFraction = fraction; int numValues = mValues.length; for (int i = 0; i < numValues; ++i) { mValues[i].calculateValue(fraction); //TypeEvaluator 函数 } if (mUpdateListeners != null) { // 通知监听器 int numListeners = mUpdateListeners.size(); for (int i = 0; i < numListeners; ++i) { mUpdateListeners.get(i).onAnimationUpdate(this); } } } |
3 通俗解析各个击破
3.1 关于ValueAnimator
(0)ValueAnimator
就是一个的TypeEvaluator
和一个TimeInterpolator
的结合体,所以该类有两个方法分别用来设置动画的TypeEvaluator
和TimeInterpolator
。 (1)setInterpolator
方法可以不调用,默认是加速减速插值器AccelerateDecelerateInterpolator
,但是如果调用且传入的参数为null的话,那么就会被设置成线性插值器LinearInterpolator
(暂时不清楚为什么要这样做)。 (2)setEvaluator
方法也可以不调用,默认会根据属性值的类型设置一个IntEvaluator
或者FloatEvaluator
。后面会讲到这类TypeEvaluator
可以看作是线性估值器"LinearTypeEvaluator"
(并没有这个说法,因故加上引号)。
参考ValueAnimator
的部分源码: