美文网首页动画
视差动画-旋转加载动画

视差动画-旋转加载动画

作者: _风听雨声 | 来源:发表于2020-03-28 14:39 被阅读0次

效果:


旋转加载动画效果
效果分析:
第一步旋转小球

1.1通过integer-array来定义显示的小球个数和颜色

1.2 Math.PI * 2 / 小球个数 得到小球所占角度的平均数,得到每个小球圆点的角度值

1.3.指定大外圆的半径,通过三角函数计算每个小球的圆点的坐标,绘制小球

1.4利用属性动画ofFloat 0到360度获取改变的角度,invalidate(),让小球旋转起来

/**
     * 旋转动画绘制
     */
    private ValueAnimator rotateAnimator;

    class RotateStatus extends AnimatorStatus {

        public RotateStatus() {
            rotateAnimator = ObjectAnimator.ofFloat(0f, (float) (2 * Math.PI));
            rotateAnimator.setDuration(ANIMATOR_DURATION);
            rotateAnimator.setRepeatCount(-1);
            rotateAnimator.setInterpolator(new LinearInterpolator());
            rotateAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    mChangeAngle = (float) animation.getAnimatedValue();
                    invalidate();
                }
            });
            rotateAnimator.start();
        }

        @Override
        void onDraw(Canvas canvas) {
            canvas.drawColor(getResources().getColor(android.R.color.white));
            for (int i = 0; i < mColorList.length; i++) {
                double angle = oneAngle * i + mChangeAngle;
                int circleCenterX = (int) (mOutRadius * Math.cos(angle));
                int circleCenterY = (int) (mOutRadius * Math.sin(angle));
                mPaint.setColor(mColorList[i]);
                canvas.drawCircle(mCenterX + circleCenterX, mCenterY + circleCenterY, mCircleRadius, mPaint);
            }
        }

        @Override
        void cancel() {
            rotateAnimator.cancel();
        }
    }
第二步拿到数据聚合向中间靠拢动画

2.1 大外圆半径就是每个小球需要变化的距离,即通过属性动画来改变大外圆的半径
2.2 通过三角函数计算小球改变的圆点坐标
2.3 AnticipateInterpolator插值器来实现开始前向外扩散一下的效果

    /**
     * 聚合动画绘制
     */
    private ValueAnimator drawCloseAnimator;

    class DrawCloseStatus extends AnimatorStatus {
        public DrawCloseStatus() {
            drawCloseAnimator = ObjectAnimator.ofFloat(mOutRadius, 0f);
            drawCloseAnimator.setDuration(ANIMATOR_DURATION / 5);
            drawCloseAnimator.setInterpolator(new AnticipateInterpolator(5f));
            drawCloseAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    mCircleDistance = (float) animation.getAnimatedValue();
                    invalidate();
                }
            });
            drawCloseAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    mAnimatorStatus = new SpreadStatus();
                }
            });
            drawCloseAnimator.start();
        }

        @Override
        void onDraw(Canvas canvas) {
            canvas.drawColor(getResources().getColor(android.R.color.white));
            for (int i = 0; i < mColorList.length; i++) {
                double angle = oneAngle * i + mChangeAngle;
                int circleCenterX = (int) (mCircleDistance * Math.cos(angle));
                int circleCenterY = (int) (mCircleDistance * Math.sin(angle));
                mPaint.setColor(mColorList[i]);
                canvas.drawCircle(mCenterX + circleCenterX, mCenterY + circleCenterY, mCircleRadius, mPaint);
            }
        }

        @Override
        void cancel() {
            drawCloseAnimator.cancel();
        }
    }
第三步向外扩散动画

3.1 向外扩散的圆的半径为控件对角线的一半,即通过三角函数斜边等于对边的平方加邻边的平方开根号
3.2 画笔Panit strokeWidth 的大小变化为控件对角线的一半 到 0
3.2 向外扩散圆的半径大小变化为0到控件对角线的一半 + Panit strokeWidth 的1/2;

/**
     * 扩散动画
     */
    private ValueAnimator spreadAnimator;

    class SpreadStatus extends AnimatorStatus {
        private float spreadDistance;
        private float changeRadius;

        public SpreadStatus() {
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setColor(getResources().getColor(android.R.color.white));
            spreadDistance = (float) Math.sqrt(mCenterX * mCenterX + mCenterY * mCenterY);
            spreadAnimator = ObjectAnimator.ofFloat(0, spreadDistance);
            spreadAnimator.setDuration(ANIMATOR_DURATION / 5);
            spreadAnimator.setInterpolator(new LinearInterpolator());
            spreadAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    changeRadius = (float) animation.getAnimatedValue();
                    invalidate();
                }
            });
            spreadAnimator.start();
        }

        @Override
        void onDraw(Canvas canvas) {
            float strokeWidth = spreadDistance - changeRadius;
            mPaint.setStrokeWidth(strokeWidth);
            canvas.drawCircle(mCenterX, mCenterY, changeRadius + strokeWidth / 2, mPaint);
        }

        @Override
        void cancel() {
            spreadAnimator.cancel();
        }
    }

实现思路都在上面了,下方附上完整代码

   <integer-array name="loading_circle_color_list">
        <item>@color/color_cd6155</item>
        <item>@color/color_48c9b0</item>
        <item>@color/color_af7ac5</item>
        <item>@color/color_f4d03f</item>
        <item>@color/color_9c640c</item>
        <item>@color/color_5dade2</item>
    </integer-array>
public class LoadingView extends View {
    private int mColorList[];
    private int mCenterX, mCenterY;
    private Paint mPaint;
    private double oneAngle;
    private int mOutRadius;
    private int mCircleRadius;
    private float mChangeAngle;
    private long ANIMATOR_DURATION = 3500;
    private AnimatorStatus mAnimatorStatus;
    private float mCircleDistance;

    public LoadingView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        mColorList = getResources().getIntArray(R.array.loading_circle_color_list);
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setDither(true);
        oneAngle = Math.PI * 2 / mColorList.length;
    }

    @Override
    protected void onSizeChanged(int width, int height, int oldw, int oldh) {
        mCenterX = width / 2;
        mCenterY = height / 2;
        mOutRadius = width / 4;
        mCircleRadius = mOutRadius / 8;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (mAnimatorStatus == null) {
            mAnimatorStatus = new RotateStatus();
        }
        mAnimatorStatus.onDraw(canvas);
    }

    public void dataDisplay() {
        if (mAnimatorStatus instanceof RotateStatus) {
            mAnimatorStatus.cancel();
            mAnimatorStatus = new DrawCloseStatus();
        }
    }

    /**
     * 旋转动画绘制
     */
    private ValueAnimator rotateAnimator;

    class RotateStatus extends AnimatorStatus {

        public RotateStatus() {
            rotateAnimator = ObjectAnimator.ofFloat(0f, (float) (2 * Math.PI));
            rotateAnimator.setDuration(ANIMATOR_DURATION);
            rotateAnimator.setRepeatCount(-1);
            rotateAnimator.setInterpolator(new LinearInterpolator());
            rotateAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    mChangeAngle = (float) animation.getAnimatedValue();
                    invalidate();
                }
            });
            rotateAnimator.start();
        }

        @Override
        void onDraw(Canvas canvas) {
            canvas.drawColor(getResources().getColor(android.R.color.white));
            for (int i = 0; i < mColorList.length; i++) {
                double angle = oneAngle * i + mChangeAngle;
                int circleCenterX = (int) (mOutRadius * Math.cos(angle));
                int circleCenterY = (int) (mOutRadius * Math.sin(angle));
                mPaint.setColor(mColorList[i]);
                canvas.drawCircle(mCenterX + circleCenterX, mCenterY + circleCenterY, mCircleRadius, mPaint);
            }
        }

        @Override
        void cancel() {
            rotateAnimator.cancel();
        }
    }

    /**
     * 聚合动画绘制
     */
    private ValueAnimator drawCloseAnimator;

    class DrawCloseStatus extends AnimatorStatus {
        public DrawCloseStatus() {
            drawCloseAnimator = ObjectAnimator.ofFloat(mOutRadius, 0f);
            drawCloseAnimator.setDuration(ANIMATOR_DURATION / 5);
            drawCloseAnimator.setInterpolator(new AnticipateInterpolator(5f));
            drawCloseAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    mCircleDistance = (float) animation.getAnimatedValue();
                    invalidate();
                }
            });
            drawCloseAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    mAnimatorStatus = new SpreadStatus();
                }
            });
            drawCloseAnimator.start();
        }

        @Override
        void onDraw(Canvas canvas) {
            canvas.drawColor(getResources().getColor(android.R.color.white));
            for (int i = 0; i < mColorList.length; i++) {
                double angle = oneAngle * i + mChangeAngle;
                int circleCenterX = (int) (mCircleDistance * Math.cos(angle));
                int circleCenterY = (int) (mCircleDistance * Math.sin(angle));
                mPaint.setColor(mColorList[i]);
                canvas.drawCircle(mCenterX + circleCenterX, mCenterY + circleCenterY, mCircleRadius, mPaint);
            }
        }

        @Override
        void cancel() {
            drawCloseAnimator.cancel();
        }
    }

    /**
     * 扩散动画
     */
    private ValueAnimator spreadAnimator;

    class SpreadStatus extends AnimatorStatus {
        private float spreadDistance;
        private float changeRadius;

        public SpreadStatus() {
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setColor(getResources().getColor(android.R.color.white));
            spreadDistance = (float) Math.sqrt(mCenterX * mCenterX + mCenterY * mCenterY);
            spreadAnimator = ObjectAnimator.ofFloat(0, spreadDistance);
            spreadAnimator.setDuration(ANIMATOR_DURATION / 5);
            spreadAnimator.setInterpolator(new LinearInterpolator());
            spreadAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    changeRadius = (float) animation.getAnimatedValue();
                    invalidate();
                }
            });
            spreadAnimator.start();
        }

        @Override
        void onDraw(Canvas canvas) {
            float strokeWidth = spreadDistance - changeRadius;
            mPaint.setStrokeWidth(strokeWidth);
            canvas.drawCircle(mCenterX, mCenterY, changeRadius + strokeWidth / 2, mPaint);
        }

        @Override
        void cancel() {
            spreadAnimator.cancel();
        }
    }

    abstract class AnimatorStatus {
        abstract void onDraw(Canvas canvas);

        void cancel() {
        }
    }
}

相关文章

网友评论

    本文标题:视差动画-旋转加载动画

    本文链接:https://www.haomeiwen.com/subject/hggjuhtx.html