android自定义View---6个小圆组成的加载动画

项目里面的一个 加载动画,是要做成一个按钮形状

这个是需求图

android自定义View---6个小圆组成的加载动画_第1张图片












这个是展示效果图:初步的图

android自定义View---6个小圆组成的加载动画_第2张图片


这是我最后实现的效果图

android自定义View---6个小圆组成的加载动画_第3张图片



首先我们说一下这个6个小球的旋转,我们都可以看出,这个六个小球也是在画一个大圆,所以我们只要把大圆的半径确定了之后,在计算每个小圆的角度,再不断的进行绘制是不是就可以了?对,没错,就是这样的。那么在这之前我们是不是应该找到中间大圆的中心点,并且计算出半径啊。

其实这个中心点就是屏幕对角线的一半,请看代码


    /**
     * 计算屏幕中心点
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mCenterX = w / 2f;
        mCenterY = h / 2f;
        //屏幕对角线一半
        mDiagonaalDist = (float) Math.sqrt((w * w + h * h) / 2);
    }
 /**
     * 画六个小圆
     */
    private void drawCircle(Canvas canvas) {
        //得到每个小圆的间隔角度
        float rotationAngle = (float) (2 * Math.PI / 6);
        //画6个小圆
        for (int i = 0; i < 6; i++) {
            /**
             * 计算角度
             * x = r*cos(a)
             * y = r*sin(a);
             */
            double angle = i * rotationAngle + mCurrentRotationAngle;//不断的更新圆点的坐标位置
            //因为最开始的计算是再屏幕的左上角,计算出每个圆点位置之后加上中心点X或者Y坐标就可以了
            float cx = (float) (mCurrentRotationRadius * Math.cos(angle) + mCenterX);
            float cy = (float) (mCurrentRotationRadius * Math.sin(angle) + mCenterY);
            mpaint.setColor(mCircleColors);//设置小圆的颜色
            canvas.drawCircle(cx, cy, mCircleRadius, mpaint);
        }
    }

动画效果代码

 /**
     * 第一个动画:小圆旋转动画
     * 要素:不断的绘制小圆--》控制左边---- 旋转的角度、公转的半径
     */
    private class RotationState extends SplashState {
        public RotationState() {
            //动画初始化
            //花1600ms,计算某个时间当前的角度是多少:0~2π中的某个值
            valueAnimator = ValueAnimator.ofFloat(0, (float) Math.PI * 2);
            valueAnimator.setInterpolator(new LinearInterpolator());//设置插值器,主要是为了小圆点的旋转时间平均,让动画没有停顿。
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {//回调监听
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    //得到某个时间点计算的结果 ----这个时间带你当前大圆旋转的角度
                    mCurrentRotationAngle = (float) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            valueAnimator.setDuration(mRotationDuration);//动画时间
            valueAnimator.setRepeatCount(ValueAnimator.INFINITE);//不断重复
            valueAnimator.start();//启动
        }


最后的代码

public class SplashView extends View {
    private float mRotationRadius = 120;//大圆(里面包含很多小圆)的半径
    private float mCircleRadius = 18;//每一个小圆的半径
    private int mCircleColors;//小圆颜色列表,在initialize方法里面初始化
    private long mRotationDuration = 1600;//大圆和小圆旋转时间
    private int mSplashBgColor = Color.WHITE;//整体的背景颜色
    /**
     * 参数,保存了一些绘制状态,会被动态的改变
     */
    //空心圆的初始半径
    private float mHoleRadius = 0f;
    //当前大圆旋转角度
    private float mCurrentRotationAngle = 0f;
    //当前大圆的半径
    private float mCurrentRotationRadius = mRotationRadius;
    //绘制圆的画笔
    private Paint mpaint = new Paint();
    //绘制背景的画笔
    private Paint mPaintBackground = new Paint();
    //屏幕中心点坐标
    private float mCenterX;
    private float mCenterY;
    //屏幕对角线一半
    private float mDiagonaalDist;
    private ValueAnimator valueAnimator;

    /**
     * 如果要写再xml里面就需要三个构造函数
     *
     * @param context
     */
    public SplashView(Context context) {
        super(context);
        init();
    }

    public SplashView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

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

    @TargetApi(Build.VERSION_CODES.M)
    private void init() {
        mpaint.setAntiAlias(true);//初始化画小圆的画笔
        mPaintBackground.setAntiAlias(true);//初始化画背景的画笔
        mPaintBackground.setStyle(Paint.Style.STROKE);//设置样式
        mPaintBackground.setColor(mSplashBgColor);//设置背景画笔颜色
        mCircleColors = getContext().getColor(R.color.mc_cir_progress_button_red);//设置小圆的颜色
    }

    /**
     * 计算屏幕中心点
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mCenterX = w / 2f;
        mCenterY = h / 2f;
        //屏幕对角线一半
        mDiagonaalDist = (float) Math.sqrt((w * w + h * h) / 2);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        //绘制动画第一个动画
        if (mstate == null) {
            mstate = new RotationState();
        }
        mstate.drawState(canvas);
        super.onDraw(canvas);
    }


    private abstract class SplashState {
        public abstract void drawState(Canvas canvas);
    }

    //这里利用一个设计模式:策略模式
    private SplashState mstate = null;

    /**
     * 第一个动画:小圆旋转动画
     * 要素:不断的绘制小圆--》控制左边---- 旋转的角度、公转的半径
     */
    private class RotationState extends SplashState {
        public RotationState() {
            //动画初始化
            //花1600ms,计算某个时间当前的角度是多少:0~2π中的某个值
            valueAnimator = ValueAnimator.ofFloat(0, (float) Math.PI * 2);
            valueAnimator.setInterpolator(new LinearInterpolator());//设置插值器,主要是为了小圆点的旋转时间平均,让动画没有停顿。
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {//回调监听
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    //得到某个时间点计算的结果 ----这个时间带你当前大圆旋转的角度
                    mCurrentRotationAngle = (float) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            valueAnimator.setDuration(mRotationDuration);//动画时间
            valueAnimator.setRepeatCount(ValueAnimator.INFINITE);//不断重复
            valueAnimator.start();//启动
        }

        public void cancle() {
            valueAnimator.cancel();
        }

        @Override
        public void drawState(Canvas canvas) {
            //绘制动画
            //1擦黑板
            drawBackground(canvas);
            //2.画小圆
            drawCircle(canvas);
        }
    }
     private void drawBackground(Canvas canvas) {
        if (mHoleRadius > 0f) {
            //得到画笔的宽度 = 对角线/2-空心圆的半径
            float strokewidth = mDiagonaalDist - mHoleRadius;
            mPaintBackground.setStrokeWidth(strokewidth);//设置画笔的宽度
            //画圆的半径 = 空心圆半径+画笔宽度/2
            float radius = mHoleRadius + strokewidth / 2;
            //空心圆的半径越来越大  画笔的宽度就越来也小
            canvas.drawCircle(mCenterX, mCenterY, radius, mPaintBackground);
        } else {
            canvas.drawColor(mSplashBgColor);
        }
    }

    /**
     * 画六个小圆
     */
    private void drawCircle(Canvas canvas) {
        //得到每个小圆的间隔角度
        float rotationAngle = (float) (2 * Math.PI / 6);
        //画6个小圆
        for (int i = 0; i < 6; i++) {
            /**
             * 计算角度
             * x = r*cos(a)
             * y = r*sin(a);
             */
            double angle = i * rotationAngle + mCurrentRotationAngle;//不断的更新圆点的坐标位置
            //因为最开始的计算是再屏幕的左上角,计算出每个圆点位置之后加上中心点X或者Y坐标就可以了
            float cx = (float) (mCurrentRotationRadius * Math.cos(angle) + mCenterX);
            float cy = (float) (mCurrentRotationRadius * Math.sin(angle) + mCenterY);
            mpaint.setColor(mCircleColors);//设置小圆的颜色
            canvas.drawCircle(cx, cy, mCircleRadius, mpaint);
        }
    }

}



你可能感兴趣的:(android自定义)