Android動畫之旅(三)----6個小球移動的軌跡動畫

6個小球移動的軌跡動畫

動畫組成:

1.貝塞爾曲線和PathMeasure結合使用。

2. mPathMeasure.getPosTan(float v,float [] pos ,float[] tan)的使用。

3.通過動畫01形成軌跡動畫。
package com.example.administrator.animationworkdemo.views;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.DecelerateInterpolator;

/**
 * Created by SuperD on 2017/2/18.
 * 小球加載的運動軌跡
 */

public class BallLoadingPathView extends View implements View.OnClickListener {
    private static final int POINT_DISTANCE = 50;
    private static final int ANIM_RUNNING_TIME = 1000;

    //小球相關的描述
    private int mPointCount = 6;
    private int mPointRadius = 20;

    //中心點
    private int centerX;
    private int centerY;
    //首尾點之前的長度(加上隱藏的那個點,實際上有7個點)
    private float mWidth;

    //起始點,結束點
    private float mPointStartX;
    private float mPointEndX;
    private float mPointY;

    //繪製路徑
    private PathMeasure mPathMeasure;
    //儲存在路徑移動過程中的點
    private float[] mPos = new float[2];
    private Path mPath;
    private float mPathLength;
    //軌跡動畫的比率
    private float mPathRatio;

    private Paint mPaint;

    private ValueAnimator mPathAnim;


    //小球運動的標籤  True的時候mPointFlag--向下 False的時候mPointFlag--- 向上
    private int mPointFlag = 1;


    public BallLoadingPathView(Context context) {
        this(context, null);
    }

    public BallLoadingPathView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

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

    private void init() {
        mPathMeasure = new PathMeasure();
        mPath = new Path();
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mPaint.setStrokeWidth(5);

        mPathAnim = ValueAnimator.ofFloat(0, 1);
        mPathAnim.setDuration(ANIM_RUNNING_TIME);
        mPathAnim.setRepeatCount(ValueAnimator.INFINITE);
        mPathAnim.setInterpolator(new DecelerateInterpolator());
        mPathAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                mPathRatio = (float) valueAnimator.getAnimatedValue();
                invalidate();
            }
        });
        mPathAnim.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationRepeat(Animator animation) {
                super.onAnimationRepeat(animation);
                mPointFlag = -mPointFlag;
            }
        });
        setOnClickListener(this);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        centerX = w / 2;
        centerY = h / 2;
        mWidth = (mPointCount - 1) * mPointRadius * 2 + (mPointCount - 1) * POINT_DISTANCE;
        mPointStartX = centerX - mWidth / 2;
        mPointEndX = centerX + mWidth / 2;
        mPointY = centerY;
        mPath.moveTo(mPointStartX, mPointY);
        mPath.quadTo(centerX, centerY + mWidth / 2, mPointEndX, mPointY);
        mPathMeasure.setPath(mPath, false);
        mPathLength = mPathMeasure.getLength();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for (int i = 0; i < mPointCount; i++) {
            if (i == 0) {
                mPathMeasure.getPosTan(mPathRatio * mPathLength, mPos, null);
                if (mPointFlag == 1) {
                    canvas.drawCircle(mPos[0], mPos[1], mPointRadius, mPaint);
                } else {
                    canvas.drawCircle(mPos[0], getSymmetryPointY(mPos[1]), mPointRadius, mPaint);
                }
            } else {
                float startPoint = mPointStartX + (POINT_DISTANCE + 2 * mPointRadius) * i;
                canvas.drawCircle(
                        startPoint - (POINT_DISTANCE + 2 * mPointRadius) * mPathRatio,
                        mPointY,
                        mPointRadius, mPaint);
            }
        }
    }

    /**
     * 獲得當前Y座標關於屏幕中心Y軸的對稱點
     *
     * @param pointY
     * @return
     */
    private float getSymmetryPointY(float pointY) {
        float symmetryPointY = 2 * centerY - pointY;
        return symmetryPointY;
    }

    @Override
    public void onClick(View view) {
        mPathAnim.start();
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章