android那些事--屬性動畫04TypeEvaluator的使用

weixin_34208283發表於2016-11-24

通過對ValueAnimatorObjectAnimator的使用,瞭解到在獲取動畫物件時只需要傳入起始和結束值系統就會自動完成值的平滑過渡,這個平滑過渡的完成就是靠TypeEvaluator這個類.還是一樣先看一下這個介面的介紹.

理論介紹

2124459-e5a22ac8a49ab0f7
這裡寫圖片描述

再看下android原始碼中FloatEvaluatorIntEvaluator這兩個子類是如何實現的.

這個是FloatEvaluator

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);
    }
}

這個是IntEvaluator

public class IntEvaluator implements TypeEvaluator<Integer> {

    /**
     * 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>int</code> or
     *                   <code>Integer</code>
     * @param endValue   The end value; should be of type <code>int</code> or <code>Integer</code>
     * @return A linear interpolation between the start and end values, given the
     *         <code>fraction</code> parameter.
     */
     
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
        int startInt = startValue;
        return (int)(startInt + fraction * (endValue - startInt));
    }
}

可以看出這是兩個非常實在的類,哈哈.

用結束值減去初始值,算出它們之間的差值,然後乘以fraction這個係數,再加上初始值,那麼就得到當前動畫的值了

實際使用

簡單需求:自定義一個View,在View中有一個Point物件用於管理座標,然後在onDraw()方法中根據Point座標進行繪製.

分析:我們已經知道資料的平滑過渡是怎麼產生的了,那麼如果可以對Point物件進行平滑過渡則自定義View就可以實現需要的動畫效果.

  1. 自定義一個Evaluator,完成Point平滑的過渡
  2. 在自定義View中啟動Point的動畫,得到不斷更新的Point物件
  3. 更新新的Point物件重新對View進行繪製

自定義的Evaluator類

public class PointEvaluator implements TypeEvaluator<Point> {
    @Override
    public Point evaluate(float fraction, Point startValue, Point endValue) {
        float resultX = startValue.getX() + fraction * (endValue.getX() - startValue.getX());
        float resultY = startValue.getY() + fraction * (endValue.getY() - startValue.getX());
        return new Point(resultX, resultY);
    }
}

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(int x) {
        this.x = x;
    }

    public float getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }
}

最終的自定義的View

public class MyView extends View {

    private Paint mPaint;
    private Point mPoint;

    public MyView(Context context) {
        super(context);
        init();
    }
    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(Color.BLUE);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mPoint == null) {
            mPoint = new Point(50, 50);
            drawCircle(canvas);
            startAnimation();
        } else {
            drawCircle(canvas);
        }
    }
    private void drawCircle(Canvas canvas) {
        canvas.drawCircle(mPoint.getX(), mPoint.getY(), 50, mPaint);
    }

    private void startAnimation() {
        Point startPoint = new Point(50, 50);
        Point endPoint = new Point(getWidth() - 50, getHeight() - 50);

        ValueAnimator animator = ValueAnimator
                .ofObject(new PointEvaluator(), startPoint, endPoint);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {

                mPoint = ((Point) animation.getAnimatedValue());
                LogUtil.i(mPoint.getX()+"------"+mPoint.getY());
                invalidate();
            }
        });
        animator.setDuration(5000);
        animator.start();
    }
}
2124459-734886f5963fa97d
這裡寫圖片描述

相關文章