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

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
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值