上一篇博客介绍了Android自定义控件中音量控制器的实现方法,没有看过的盆友可以传送到http://blog.csdn.net/a253664942/article/details/45017283看看。今天准备给大家介绍一下圆形进度条的实现方式。
首先看一下最终的实现效果,来上图:
进度条的背景进度的颜色、进度的颜色以及字体的颜色、圆环的半径和宽度都可以使用自定义属性来改变,另外,还添加了一个onProgressListener监听器,其中有一个onEnd回调方法,用来处理当进度条到达最大值时的事件。各位看官如果喜欢,也可以自己加一些回调方法,比如onStart方法用来监听到进度开始执行的回调方法。
首先自定义一个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();
}
在构造方法中 获得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>
在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的坐标加上直径。
测量完控件的宽高之后,来到最重要的一步: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进度,只要进度条当前值小于最大值,则刷新视图重新绘制。最后,当进度条到达最大值时,我们调用回调方法。
在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);
}
});
}
好了,收工!这次的自定义控件的实现中涉及到了很多的知识点:自定义属性的使用,自定义视图的绘制以及自己定义的回调接口。
其实大家可以发现,将这个案例改一改,我们就可以实现另外一种效果:小米音量控制器。很简单,只要将中间的字换成图片就可以了,然后改一下进度条的颜色~~
各位如果喜欢的话,可以留个言 点个赞~!
**
**