Android自定义控件(二)——圆形进度条以及回调方法

来源:互联网 发布:龙华数据恢复 编辑:程序博客网 时间:2024/06/15 21:06

(一)引言

上一篇博客介绍了Android自定义控件中音量控制器的实现方法,没有看过的盆友可以传送到http://blog.csdn.net/a253664942/article/details/45017283看看。今天准备给大家介绍一下圆形进度条的实现方式。
首先看一下最终的实现效果,来上图:
自定义圆形进度条样式
进度条的背景进度的颜色、进度的颜色以及字体的颜色、圆环的半径和宽度都可以使用自定义属性来改变,另外,还添加了一个onProgressListener监听器,其中有一个onEnd回调方法,用来处理当进度条到达最大值时的事件。各位看官如果喜欢,也可以自己加一些回调方法,比如onStart方法用来监听到进度开始执行的回调方法。

(二)代码实现

1.自定义类

首先自定义一个CircleProgressView类继承View,然后声明各种属性:进度条的半径,宽度,颜色等以及回调函数。源码中有很详细的注释,一看就明白,这里就不再赘述了。

public class CircleProgressView extends View {private Paint mPaintBackground; // 绘制背景圆环的画笔private Paint mPaintProgress; // 绘制背景进度的画笔private Paint mPaintText; // 绘制背景字体的画笔private int bgColor = Color.WHITE; // 背景圆环的颜色private int textColor = Color.CYAN; // 字体的颜色private int progressColor = Color.CYAN; // 进度条的颜色private float mStrokeWidth = 10;// 背景圆环的宽度private float mRadius = 60; // 背景圆环的半径private RectF rectPro;// 进度条的绘制外接矩形private int mProgress = 0; // 当前进度private int mMaxProgress = 100; // 最大进度private int mWidth, mHeight;private onProgressListener mOnProgressListener;public void setOnProgressListener(onProgressListener mOnProgressListener) {this.mOnProgressListener = mOnProgressListener;}/** * 回调接口 *  */public  interface onProgressListener{/** * 回调函数 当进度条满时调用此方法 */public void onEnd(); }

2.获得自定义属性

在构造方法中 获得xml文件中指定的自定义属性的值,以及初始化画笔。

public CircleProgressView(Context context, AttributeSet attrs,            int defStyleAttr) {        super(context, attrs, defStyleAttr);        // TODO Auto-generated constructor stub        if(attrs!=null){            TypedArray ta = context.obtainStyledAttributes(attrs,                    R.styleable.CircleProgress);            int count = ta.getIndexCount();            for (int i = 0; i < count; i++) {                int attr = ta.getIndex(i);                switch (attr) {                case R.styleable.CircleProgress_radius:                    mRadius = ta.getDimension(R.styleable.CircleProgress_radius, mRadius);                    break;                case R.styleable.CircleProgress_strokeWidth:                    mStrokeWidth = ta.getDimension(R.styleable.CircleProgress_strokeWidth, mStrokeWidth);                    break;                case R.styleable.CircleProgress_bgColor:                    bgColor = ta.getColor(R.styleable.CircleProgress_bgColor, bgColor);                    break;                case R.styleable.CircleProgress_progressColor:                    progressColor = ta.getColor(R.styleable.CircleProgress_progressColor, progressColor);                    break;                case R.styleable.CircleProgress_android_textColor:                    textColor = ta.getColor(R.styleable.CircleProgress_android_textColor, textColor);                    break;                }            }            ta.recycle();        }        initPaint();    }

initPaint方法是初始化画笔的函数。

private void initPaint() {        mPaintBackground = new Paint();        mPaintBackground.setColor(bgColor);        // 设置抗锯齿        mPaintBackground.setAntiAlias(true);        // 设置防抖动        mPaintBackground.setDither(true);        // 设置样式为环形        mPaintBackground.setStyle(Style.STROKE);        // 设置环形的宽度        mPaintBackground.setStrokeWidth(mStrokeWidth);        mPaintProgress = new Paint();        mPaintProgress.setColor(progressColor);        // 设置抗锯齿        mPaintProgress.setAntiAlias(true);        // 设置防抖动        mPaintProgress.setDither(true);        // 设置样式为环形        mPaintProgress.setStyle(Style.STROKE);        // 设置环形的宽度        mPaintProgress.setStrokeWidth(mStrokeWidth);        mPaintText = new Paint();        mPaintText.setColor(textColor);        // 设置抗锯齿        mPaintText.setAntiAlias(true);        mPaintText.setTextAlign(Align.CENTER);        mPaintText.setTextSize(40);    }

progressColor、bgColor等都是自定义的属性,在attrs.xml文件中声明。见名知意,这些属性值的意思应该不难理解。

attrs.xml

<resources xmlns:android="http://schemas.android.com/apk/res/android">    <attr name="bgColor" format="color|reference" />    <attr name="progressColor" format="color|reference" />    <attr name="radius" format="dimension" />    <attr name="strokeWidth" format="dimension" />    <declare-styleable name="CircleProgress">        <attr name="android:textColor" />        <attr name="bgColor" />        <attr name="progressColor" />        <attr name="radius" />        <attr name="strokeWidth" />    </declare-styleable></resources>

3.测量控件宽高

在onMeasure方法中测量控件的宽高,RectPro是进度条圆环外接矩形的范围。

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        // TODO Auto-generated method stub        mWidth = getRealSize(widthMeasureSpec);        mHeight = getRealSize(heightMeasureSpec);        setMeasuredDimension(mWidth, mHeight);    }private int getRealSize(int measureSpec) {        int result = -1;        int mode = MeasureSpec.getMode(measureSpec);        int size = MeasureSpec.getSize(measureSpec);        if (mode == MeasureSpec.AT_MOST || mode == MeasureSpec.UNSPECIFIED) { // 这两种模式需要自己计算            result = (int) (mRadius * 2 + mStrokeWidth*2);        } else {            result = size;        }        return result;    }    private void initRect() {        if (rectPro == null) {            rectPro = new RectF();            int viewSize = (int) (mRadius * 2);            int left = (mWidth - viewSize) / 2;            int top = (mHeight - viewSize) / 2;            int right = left + viewSize;            int bottom = top + viewSize;            rectPro.set(left, top, right, bottom);        }

这里可以画个图来便于大家理解。
这里写图片描述
在上图中,黑色边框内的范围代表父容器。而我们的控件的宽度等于直径的长度+加上边框的宽度*2。即 width =radius *2 + strokeWidth*2;
高度同理。
绿色的边框表示RectPro即进度条圆环外接矩形的范围。RectPro的left和top的坐标等于控件的宽度减去圆环直径然后除以2;right和bottom的坐标等于left的坐标加上直径。

4.绘制进度条

测量完控件的宽高之后,来到最重要的一步:onDraw方法中绘制进度条。

protected void onDraw(Canvas canvas) {        float angle = mProgress / (mMaxProgress * 1.0f) * 360; // 圆弧角度        initRect();        //绘制背景圆环        canvas.drawCircle(mWidth / 2, mHeight / 2, mRadius,                mPaintBackground);        //绘制进度条        canvas.drawArc(rectPro, -90, angle, false, mPaintProgress);        //绘制字体        canvas.drawText(mProgress + "%", mWidth / 2, mHeight / 2, mPaintText);        if (mProgress < mMaxProgress) {            mProgress += 2;            invalidate();        }        //当进度到达最大值时  调用此函数        if(mOnProgressListener != null){        if(mProgress == mMaxProgress){                mOnProgressListener.onEnd();            }        }    }

我们控制进度条每次迭代2进度,只要进度条当前值小于最大值,则刷新视图重新绘制。最后,当进度条到达最大值时,我们调用回调方法。

5.使用自定义控件

在activity_main.xml中引用我们的自定义控件并设置属性。并在activity中使用我们的回调方法:当进度条到达最大值时,设置其进度为0,最终的效果时:进度条无限循环从0到100;

activity_main.xml

   <com.custom.circleprogressview.CircleProgressView        android:id="@+id/pro"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        app:bgColor="#FFFF00"        app:progressColor="#FF0F00"        app:radius = "100dip"        app:strokeWidth = "10dip"       />

activity中调用

protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        final CircleProgressView progressView = (CircleProgressView) findViewById(R.id.pro);        progressView.setOnProgressListener(new onProgressListener() {            public void onEnd() {                // TODO Auto-generated method stub                progressView.setProgress(0);            }        });    }

(三)总结

好了,收工!这次的自定义控件的实现中涉及到了很多的知识点:自定义属性的使用,自定义视图的绘制以及自己定义的回调接口。
其实大家可以发现,将这个案例改一改,我们就可以实现另外一种效果:小米音量控制器。很简单,只要将中间的字换成图片就可以了,然后改一下进度条的颜色~~
这里写图片描述
各位如果喜欢的话,可以留个言 点个赞~!
**

附上源码

**

1 0