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

视差动画-旋转加载动画

作者: _风听雨声 | 来源:发表于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