实现一个Material效果的ProgressBar

先来看看效果:
实现一个Material效果的ProgressBar_第1张图片

分析下难点:
1. 动画的实现;
2. 边界的控制;
3. 状态保存与恢复;
4. 两种状态的实现,loading状态(不停旋转)、progress状态。

分别来看下。
1. 动画如何实现:
将动画进行拆解,可以发现它其实是一个弧不断变长变短的一个过程+弧本身在绕圆形转动两部分组成。
所以可以分开来处理,弧度变长变短可以通过canvas.drawArc的参数startAngle/SweeepAngle控制,只要改变这两个值即可实现效果。怎么改变?有几种方案,1是通过hander+thread;2是通过View.post();3是通过PropertyAnimation.
弧本身绕圆心运动可以通过Canvas.rotate实现。

private static final float delta = 6f;
    private float temp = 0;
    class AnimRunnable implements Runnable{
        @Override
        public void run() {
            if (mStartAngle == temp) {
                mSweepAngle += delta;
            }
            if (mSweepAngle >= 280 || mStartAngle > temp) {
                mStartAngle += delta;
                if(mSweepAngle > 20) {
                    mSweepAngle -= delta;
                }
            }
            if (mStartAngle > temp + 280) {
                temp = mStartAngle;
                mStartAngle = temp;
                mSweepAngle = 20;
            }
            postInvalidate();
            postDelayed(this,mSpinSpeed);
        }
    }

2.边界的控制:
需要在onMeasure中控制。在onSizeChanged方法中可以拿到最终的width、height,通过width/height就可以控制progressbar的边界了。
需要注意的是,边界需要是正方形的,所以得考虑宽高不相等的情况以及四个方向padding的大小。

 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //计算自己需要的宽度和高度
        int width = mCircleRadius*2;
        int height = mCircleRadius*2;
        //考虑父容器的测量规则
        setMeasuredDimension(getResolvedSize(width, widthMeasureSpec), getResolvedSize(height, heightMeasureSpec));
    }
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        int paddingLeft = getPaddingLeft();
        int paddingTop = getPaddingTop();
        int paddingRight = getPaddingRight();
        int paddingBottom = getPaddingBottom();
        //简化处理,以最大的padding作为padding
        int padding = Math.max(Math.max(paddingLeft, paddingRight), Math.max(paddingTop, paddingBottom));
        int diameter;
        //保证bounds是一个正方形
        if(w >= h){
            diameter = h;
            mBounds = new RectF(padding+mBarWidth+(w-h)/2,padding+mBarWidth,diameter-padding-mBarWidth+(w-h)/2,diameter-padding-mBarWidth);
        }else if(w < h){
            diameter = w;
            mBounds = new RectF(padding+mBarWidth,padding+mBarWidth+(h-w)/2,diameter-padding-mBarWidth,diameter-padding-mBarWidth+(h-w)/2);
        }
    }

3.状态的保存与恢复:
progressbar的状态不能因为横竖屏切换等问题丢失,所以需要通过重写onSaveInstanceState/onRestoreInstanceState来保存/恢复状态.

@Override
    protected void onRestoreInstanceState(Parcelable state) {
        if(! (state instanceof SavedState)){
            super.onRestoreInstanceState(state);
            return;
        }
        //先恢复父类的状态
        SavedState savedState = (SavedState) state;
        super.onRestoreInstanceState(savedState.getSuperState());
        //在恢复自己的状态
        this.mCurMode = savedState.mCurMode == 0 ? Mode.INDETERMINATE : Mode.DETERMINATE;
        this.mRimWidth = savedState.mRimWidth;
        this.mRimColor = savedState.mRimColor;
        this.mBarColor = savedState.mBarColor;
        this.mBarWidth = savedState.mBarWidth;
        this.showRim = savedState.showRim;
        this.isAnimStart = savedState.isAnimStart;
        this.mProgress = savedState.mProgress;
    }
    @Override
    protected Parcelable onSaveInstanceState() {
        //相当于是做了一层包装
        //先保存父类的状态,然后包装,再保存自己的状态
        Parcelable parcelable = super.onSaveInstanceState();
        SavedState savedState = new SavedState(parcelable);
        savedState.mCurMode = (this.mCurMode == Mode.INDETERMINATE) ? 0 : 1;
        savedState.mRimWidth = this.mRimWidth;
        savedState.mRimColor = this.mRimColor;
        savedState.mBarColor = this.mBarColor;
        savedState.mBarWidth = this.mBarWidth;
        savedState.showRim = this.showRim;
        savedState.isAnimStart = this.isAnimStart;
        savedState.mProgress = this.mProgress;
        return savedState;
    }

4.两种状态的实现:
自然是通过一个变量记录当前模式,在onDraw中通过判断模式进行不同的绘制操作。

地址:​https://github.com/Rowandjj/MaterialProgressBar/

你可能感兴趣的:(android,progress-bar)