Android動畫之自定義Evaluator實現彈球效果

前言

今天給大家帶來的是自定義Evaluator實現彈球效果,我們先給大家來個效果圖。

效果圖

下面我們介紹具體代碼流程

1. 自定義Point類

public class Point {

    private int radius;

    public Point(int radius) {
        this.radius = radius;
    }

    public int getRadius() {
        return radius;
    }

    public void setRadius(int radius) {
        this.radius = radius;
    }
}

2. 自定義PointEvaluator實現TypeEvaluator接口

class PointEvaluator implements TypeEvaluator<Point> {

    /**
     * @param fraction   動畫變化中的浮點參數,0-1
     * @param startValue 動畫開始時的Point對象
     * @param endValue   動畫結束時的Point對象
     * @return 動畫過程中通過計算獲取半徑並返回一個新的Point對象
     */
    @Override
    public Point evaluate(float fraction, Point startValue, Point endValue) {
        int startRadius = startValue.getRadius();
        int endRadius = endValue.getRadius();
        int newRadius = (int) (startRadius + fraction * (endRadius - startRadius));
        return new Point(newRadius);
    }
}

3. 自定義PointView

  • 定義彈球屬性attrs
<declare-styleable name="PointView">
        <attr name="point_color" format="color" />
</declare-styleable>
  • 獲取自定義屬性,這裏我們只定義了一個彈球顏色屬性。
    private void initAttrs(Context context, AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.PointView);
        mColor = typedArray.getColor(R.styleable.PointView_point_color, DEFAULT_COLOR);
        typedArray.recycle();
    }
  • 初始化畫筆
private void initPaint() {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(mColor);
    }
  • 重寫onMeasure方法
@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        /**
         * 測量view的寬高
         */
        if (widthMode == MeasureSpec.AT_MOST) {
            widthSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_WIDTH, getResources().getDisplayMetrics()) + getPaddingLeft() + getPaddingRight();
        }
        if (heightMode == MeasureSpec.AT_MOST) {
            heightSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_HEIGHT, getResources().getDisplayMetrics()) + getPaddingTop() + getPaddingBottom();
        }
        /**
         * 使用setMeasureDimension方法確定view的最終寬和高
         */
        setMeasuredDimension(widthSize, heightSize);
    }
  • 在onSizeChanged中獲取view的最終寬度和高度
    這裏minValue是取寬度和高度中的較小值
@Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        /**
         * 在onSizeChanged重載方法中獲取view的最終寬度和高度
         */
        width = w;
        height = h;
        /**
         * 使用width減去左右的padding
         * 使用height減去上下的padding
         * 並取兩者中的最小值用來確定最大彈球的半徑
         */
        minValue = Math.min(width - getPaddingLeft() - getPaddingRight(), height - getPaddingTop() - getPaddingBottom());
    }
  • 接下來是動畫的實現,使用ValueAnimator的ofObject()實現彈球動畫
public void startAnimation() {
        /**
         * 使用ValueAnimator.ofObject()方法並使用自定義的Evaluator實現動畫
         */
        ValueAnimator animator = ValueAnimator.ofObject(new PointEvaluator(), new Point(0), new Point(minValue * 2 / 5));
        animator.setDuration(2000);
        /**
         * 設置插值器爲BounceInterpolator,其效果爲:動畫結束的時候彈起
         */
        animator.setInterpolator(new BounceInterpolator());
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                /**
                 * 通過getAnimatedValue獲取我們變化中的Point對象
                 */
                mPoint = (Point) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        animator.start();
    }
  • 最後是在onDraw函數中繪製彈球
@Override
    protected void onDraw(Canvas canvas) {
        if (mPoint != null) {
            canvas.drawCircle(width / 2, height / 2, mPoint.getRadius(), mPaint);
        }
    }

4. xml中的引用

<com.asiatravel.atpointview.view.PointView
        android:id="@+id/third_point_view"
        android:layout_width="150dp"
        android:layout_height="200dp"
        android:layout_below="@id/second_point_view"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="10dp"
        android:background="@color/colorPrimary"
        app:point_color="#0ff" />

5. 動畫實現

在代碼中獲取PointView的實例然後調用startAnimation()方法實現彈球動畫 MainActivity.java

public class MainActivity extends AppCompatActivity {

    private PointView pointView;
    private PointView secondPointView;
    private PointView thirdPointView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        pointView = (PointView) findViewById(R.id.point_view);
        secondPointView = (PointView) findViewById(R.id.second_point_view);
        thirdPointView = (PointView) findViewById(R.id.third_point_view);

        findViewById(R.id.animation_button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                pointView.startAnimation();
                secondPointView.startAnimation();
                thirdPointView.startAnimation();
            }
        });
    }
}

總結

以上就是關於今天自定義Evaluator的全部內容,不懂的童鞋可以留言或者發郵件,另外有需要源碼的小夥伴可以去github下載,點擊跳轉到github源碼地址,希望大家多多star!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章