自定義啓動頁動畫

今天學習了一下自定義 View 實現啓動頁面動畫到效果,上一下效果圖

簡單說一下過程

1、首先畫白色背景和六個不同顏色到小球

白色背景直接  canvas.drawColor(backgroundColor);

小球這裏說一下,六個小球圍成一個圓,那麼我們就先要計算出來兩個小球之間的角度是多少

獲取圓的周長除以小球個數

//先獲取圓球之間的角度 圓周長 2PI
float rotateAngle = (float) ((Math.PI * 2) / circleColor.length);

然後 for 循環繪製小球

canvas.drawCircle(float cx, float cy, float radius, @NonNull Paint paint) 

首先需要確定圓心座標,半徑是咱們規定好的

計算cx,cy需要一點點三角函數的知識

如圖

貼上計算代碼

        //先獲取圓球之間的角度 圓周長 2PI
        float rotateAngle = (float) ((Math.PI * 2) / circleColor.length);
        for (int i = 0; i < circleColor.length; i++) {
            //x=r*cons(a)+cenX
            //y=r*sin(a)+cenY
            float angle = i * rotateAngle + mCurrentRotateAngle;
            float cx = (float) (Math.cos(angle) * mCurrentRotateRadius + mCenterX);
            float cy = (float) (Math.sin(angle) * mCurrentRotateRadius + mCenterY);

            mPaint.setColor(circleColor[i]);
            canvas.drawCircle(cx, cy, smallCircleRadius, mPaint);
        }

然後我們在寫一個 ValueAnimator 用來控制小球旋轉的

            valueAnimator = ValueAnimator.ofFloat(0, (float) (Math.PI * 2));//從0開始  圓的一週結束
            valueAnimator.setRepeatCount(2);//次數
            valueAnimator.setDuration(mRotateDuration);//時長
            valueAnimator.setInterpolator(new LinearInterpolator());//勻速
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    mCurrentRotateAngle = (float) animation.getAnimatedValue();
                    invalidate();
                }
            });
            valueAnimator.addListener(new AnimatorListenerAdapter() {

                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    splashState = new MerginState();
                }
            });
            valueAnimator.start();

這個時候就可以看到六個小球在屏幕中間 開始旋轉了

2、旋轉完後 小球開始擴散後中心聚合

            valueAnimator = ValueAnimator.ofFloat(smallCircleRadius, circleRadius);
            valueAnimator.setDuration(mRotateDuration);
            valueAnimator.setInterpolator(new OvershootInterpolator(10f));
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    mCurrentRotateRadius = (float) animation.getAnimatedValue();
                    invalidate();
                }
            });
            valueAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    splashState = new ExpandState();
                }
            });
            valueAnimator.reverse();

3、最後就是我們的波紋效果了

            valueAnimator = ValueAnimator.ofFloat(smallCircleRadius, mDistance);
            valueAnimator.setDuration(mRotateDuration);
            valueAnimator.setInterpolator(new LinearInterpolator());
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    mCurrentHoleRadius = (float) animation.getAnimatedValue();
                    invalidate();
                }
            });
            valueAnimator.start();

到此炫酷的啓動動畫就已經完成了,是不是很簡單那,上一個完整的自己的 View 類

 

/**
 * @author wavewave
 * @CreateDate: 2019-07-16 22:46
 * @Description:
 * @Version: 1.0
 */
public class SplashView extends View {

    //背景顏色
    private int backgroundColor = Color.WHITE;
    private int[] circleColor = new int[]{
            Color.RED, Color.GREEN, Color.BLUE,
            Color.GRAY, Color.DKGRAY, Color.BLACK};
    private int smallCircleRadius = 10;
    private int circleRadius = 99;
    private float mCenterX, mCenterY;
    private float mDistance;
    private Paint mPaint;
    private SplashState splashState;
    private int mRotateDuration = 800;
    private float mCurrentRotateRadius = circleRadius;

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

    public SplashView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);

    }

    public SplashView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mPaint = new Paint();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mCenterX = w * 1f / 2;
        mCenterY = h * 1f / 2;
        mDistance = (float) (Math.hypot(w, h) / 2);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (splashState == null) {
            splashState = new RotateState();
        }
        splashState.drawState(canvas);

    }
    //動畫效果 6個不同顏色的球圍城一個圓 ,開始旋轉。然後擴散再聚合到中心,最後水波紋效果

    /**
     * 抽象類
     * 表示繪製狀態
     */
    public abstract class SplashState {
        abstract void drawState(Canvas canvas);
    }

    /**
     * 繪製背景顏色
     *
     * @param canvas
     */
    private void drawBackground(Canvas canvas) {
        if (mCurrentHoleRadius > 0) {//第三種動畫 繪製空心圓
            float strokeWidth = mDistance - mCurrentHoleRadius;
            float radius = strokeWidth / 2 + mCurrentHoleRadius;
            mPaint.setStrokeWidth(radius);
            canvas.drawCircle(mCenterX, mCenterY, radius, mPaint);
        } else {
            canvas.drawColor(backgroundColor);
        }
    }

    /**
     * 繪製小球
     *
     * @param canvas
     */
    private void drawCircle(Canvas canvas) {
        //先獲取圓球之間的角度 圓周長 2PI
        float rotateAngle = (float) ((Math.PI * 2) / circleColor.length);
        for (int i = 0; i < circleColor.length; i++) {
            //x=r*cons(a)+cenX
            //y=r*sin(a)+cenY
            float angle = i * rotateAngle + mCurrentRotateAngle;
            float cx = (float) (Math.cos(angle) * mCurrentRotateRadius + mCenterX);
            float cy = (float) (Math.sin(angle) * mCurrentRotateRadius + mCenterY);

            mPaint.setColor(circleColor[i]);
            canvas.drawCircle(cx, cy, smallCircleRadius, mPaint);
        }

    }

    private float mCurrentRotateAngle;
    private ValueAnimator valueAnimator;

    //1 旋轉
    private class RotateState extends SplashState {


        public RotateState() {
            valueAnimator = ValueAnimator.ofFloat(0, (float) (Math.PI * 2));//從0開始  圓的一週結束
            valueAnimator.setRepeatCount(2);//次數
            valueAnimator.setDuration(mRotateDuration);//時長
            valueAnimator.setInterpolator(new LinearInterpolator());//勻速
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    mCurrentRotateAngle = (float) animation.getAnimatedValue();
                    invalidate();
                }
            });
            valueAnimator.addListener(new AnimatorListenerAdapter() {

                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    splashState = new MerginState();
                }
            });
            valueAnimator.start();
        }

        @Override
        void drawState(Canvas canvas) {
            //繪製白色背景
            drawBackground(canvas);
            //繪製圓
            drawCircle(canvas);
        }
    }
    //2 擴展聚合

    private class MerginState extends SplashState {
        public MerginState() {
            valueAnimator = ValueAnimator.ofFloat(smallCircleRadius, circleRadius);
            valueAnimator.setDuration(mRotateDuration);
            valueAnimator.setInterpolator(new OvershootInterpolator(10f));
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    mCurrentRotateRadius = (float) animation.getAnimatedValue();
                    invalidate();
                }
            });
            valueAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    splashState = new ExpandState();
                }
            });
            valueAnimator.reverse();
        }

        @Override
        void drawState(Canvas canvas) {
            //繪製白色背景
            drawBackground(canvas);
            //繪製圓
            drawCircle(canvas);
        }
    }

    private float mCurrentHoleRadius;

    //3 波紋效果
    private class ExpandState extends SplashState {

        public ExpandState() {
            valueAnimator = ValueAnimator.ofFloat(smallCircleRadius, mDistance);
            valueAnimator.setDuration(mRotateDuration);
            valueAnimator.setInterpolator(new LinearInterpolator());
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    mCurrentHoleRadius = (float) animation.getAnimatedValue();
                    invalidate();
                }
            });
            valueAnimator.start();
        }

        @Override
        void drawState(Canvas canvas) {
            drawBackground(canvas);
        }
    }

}

如果有什麼不對地方,請大家多多指正!歡迎評論

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