Android 属性动画探究(二)——TypeEvaluator解析与自定义

来源:互联网 发布:c语言点滴 epub 编辑:程序博客网 时间:2024/05/01 16:13

1、TypeEvaluator



这里将主要阐述一下上图的第三步,关于TypeEvaluator的一些解析。上一篇中已经知道Interpolator的作用是控制动画的完成进度变化快慢的,那TypeEvaluator的作用又是什么?
简言之,TypeEvaluator是直接改变动画的属性值的,比如要改变颜色属性,可以直接改变其值为"#FFFFFF",而Interpolator改变的是进度,如可以直接指定瞬间完成动画整体的80%。但是两者不是孤立存在的,不是各自改变各自的东西,他们之间又有着什么样的爱恨纠葛?

2、系统实现的TypeEvaluator

先看一下上一篇用到的 ValueAnimator.ofFloat的默认实现
 /**     * Internal function, called by ValueAnimator, to set up the TypeEvaluator that will be used     * to calculate animated values.     */    void init() {        if (mEvaluator == null) {            // We already handle int and float automatically, but not their Object            // equivalents            mEvaluator = (mValueType == Integer.class) ? sIntEvaluator :                    (mValueType == Float.class) ? sFloatEvaluator :                    null;        }        if (mEvaluator != null) {            // KeyframeSet knows how to evaluate the common types - only give it a custom            // evaluator if one has been set on this class            mKeyframeSet.setEvaluator(mEvaluator);        }    }

可见默认设置为sFloatEvaluator
    private static final TypeEvaluator sFloatEvaluator = new FloatEvaluator();

** * This evaluator can be used to perform type interpolation between <code>float</code> values. */public class FloatEvaluator implements TypeEvaluator<Number> {    /**     * 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 * (v1 - v0)</code>,     * where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,     * and <code>t</code> is <code>fraction</code>.     *     * @param fraction   The fraction from the starting to the ending values     * @param startValue The start value; should be of type <code>float</code> or     *                   <code>Float</code>     * @param endValue   The end value; should be of type <code>float</code> or <code>Float</code>     * @return A linear interpolation between the start and end values, given the     *         <code>fraction</code> parameter.     */    public Float evaluate(float fraction, Number startValue, Number endValue) {        float startFloat = startValue.floatValue();        return startFloat + fraction * (endValue.floatValue() - startFloat);    }}
分析FloatEvaluator ,主要是实现了evaluate方法,其中的参数fraction这个至关重要,它便是开始提到问题的答案,是Interpolator中返回的动画进度。把Interpolator和TypeEvaluator联系起来。故此参数是动画的进度完成百分比。startValue  我们设置的动画初始值,endValue   我们设置的动画结束值。这里返回值是:开始值+动画完成百分比*(结束值-开始值)。显然这是线性变化关系返回此刻动画的属性值变化到哪个具体数值了。这个值我们在动画监听中获取到。
 public void onAnimationUpdate(ValueAnimator animation) {                cy = (Float) animation.getAnimatedValue();             // ...            }
这里就明白了整个流程,通过ofFloat方法传人要设置的动画变化范围值,Interpolator中返回动画当前进度百分比传人到TypeEvaluator中,TypeEvaluator根据这个百分比来计算当前的动画属性值具体应该是多少。如果需要获取当前这个属性的具体值则在onAnimationUpdate中获取。

3、自己实现TypeEvaluator

ValueAnimator与ObjectAnimator中都有ofObject(TypeEvaluator evaluator, Object... values) 这个方法,其中第一个参数便可使用自己实现的TypeEvaluator。在定义Interpolator时只能使动画进度变化按特定函数关系执行,在这里便可以使得动画的属性值按特定的函数关系变化。下面描述一个使小球沿着等幅周期振荡函数进行运动的例子。
定义一个类封装坐标值(系统也有实现-- android.graphics.Point;):
/** * 坐标点 */public class Point {    private float x;    private float y;    public Point(float x, float y) {        this.x = x;        this.y = y;    }    public float getX() {        return x;    }    public void setX(float x) {        this.x = x;    }    public float getY() {        return y;    }    public void setY(float y) {        this.y = y;    }}
定义OscillationEvaluator:
 /**     * 等幅振荡     */    class OscillationEvaluator implements TypeEvaluator {        @Override        public Object evaluate(float fraction, Object startValue, Object endValue) {            Point startPoint = (Point) startValue;            Point endPoint = (Point) endValue;            float x = startPoint.getX() + fraction * (endPoint.getX() - startPoint.getX());//x坐标线性变化            float y = 120 * (float) (Math.sin(0.01 * Math.PI * x)) + getHeight() / 2;//y坐标取相对应函数值            return new Point(x, y);        }    }
函数图像:

动画设置:
/**     * 小球动画     */    private void startAnimationMotion() {        Point startPoint = new Point(mRadius, getHeight() / 2);        Point endPoint = new Point(getWidth() - mRadius, 0);        ValueAnimator animator = ValueAnimator.ofObject(new OscillationEvaluator(), startPoint, endPoint);        animator.setDuration(7000).setRepeatCount(3);        animator.addUpdateListener(new AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator animation) {                currentPoint = (Point) animation.getAnimatedValue();                invalidate();            }        });        animator.setInterpolator(new LinearInterpolator());//设置插值器        animator.start();    }

这里需要设置为LinearInterpolator保证x坐标线性变化。

绘制图像:
  @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        width = getWidth();        height = getHeight();        mPaint.setStyle(Style.FILL);        mPaint.setAntiAlias(true);        if (currentPoint == null) {            startAnimationMotion();// 执行动画        }        mPaint.setColor(Color.WHITE);        canvas.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2, mPaint);        mPaint.setColor(Color.MAGENTA);        canvas.drawCircle(currentPoint.getX(), currentPoint.getY(), mRadius, mPaint);    }
效果:

4、总结

以上便是对Interpolator、TypeEvaluator的一些见解。Interpolator负责调节动画进度变化快慢,TypeEvaluator负责改变动画最终的属性值,它们之间以Interpolator返回的当前进度值相联系。文中多以路径变化举例,当然属性动画是可以根据需要作用于其他属性的,通过对Interpolator、TypeEvaluator的自定义,写出丰富效果。当然,一般不需要同时自己实现两者。


下载源码

0 0