在项目中有个需求,要实现如下图所示的进度条:
下面我们就用自定义的View来实现它。
package cn.yubo.roundprogress;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
/**
* 自定义圆环进度条
* @author yubo<br/>
* 2015年1月23日
*/
public class RoundProgressView extends View {
private int centerX;//圆环的中心X坐标
private int centerY;//圆环的中心Y坐标
private int radius;//圆环的半径
private Paint paint;//圆环的画笔
private Paint progressPaint;//圆环中进度的画笔
private int progress;//当前进度
private int maxProgress = 100;//最大进度,默认为100
public RoundProgressView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public RoundProgressView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public RoundProgressView(Context context) {
super(context);
init();
}
/**创建RoundProgressView时通过该方法初始化*/
private void init(){
paint = new Paint();
paint.setStrokeWidth(20);
paint.setStyle(Paint.Style.STROKE);
paint.setAntiAlias(true);
paint.setColor(Color.parseColor("#E7E7E7"));//灰色的圆环
progressPaint = new Paint();
progressPaint.setAntiAlias(true);
progressPaint.setColor(Color.parseColor("#1082F5"));//蓝色的进度
progressPaint.setStrokeWidth((float) 20.0);
progressPaint.setStyle(Style.STROKE);
progressPaint.setStrokeCap(Paint.Cap.ROUND);//让画笔画出的线条是圆的
}
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
super.onLayout(changed, left, top, right, bottom);
//计算圆环的圆心坐标
centerX = getMeasuredWidth() / 2;
centerY = getMeasuredHeight() / 2;
//计算圆环的半径,这里取View的长宽中较小值的1/2
radius = (centerX > centerY ? centerY : centerX) / 2;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//画出灰色的圆环
canvas.drawCircle(centerX, centerY, radius, paint);
//构造圆环的外围矩形
RectF rectF = new RectF(centerX - radius, centerY - radius, centerX + radius, centerY + radius);
//计算显示的进度
int progressAngle = (progress * 360) / maxProgress;
//画出进度,注意这里的270表示从圆环的最顶部开始画,如果270替换为0,则是从圆环的右端开始画
canvas.drawArc(rectF, 270, progressAngle, false, progressPaint);
}
public int getProgress() {
return progress;
}
public void setProgress(int progress) {
this.progress = progress;
postInvalidate();
}
public int getMaxProgress() {
return maxProgress;
}
public void setMaxProgress(int maxProgress) {
this.maxProgress = maxProgress;
}
}
在布局文件中,我们这么使用上面的类:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<cn.yubo.roundprogress.RoundProgressView
android:id="@+id/roundProgress"
android:layout_width="fill_parent"
android:layout_height="300dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" />
</RelativeLayout>
package cn.yubo.roundprogress;
import android.os.Bundle;
import android.app.Activity;
public class MainActivity extends Activity {
private RoundProgressView roundProgress;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
roundProgress = (RoundProgressView) findViewById(R.id.roundProgress);
roundProgress.setProgress(35);
}
}
运行的效果如下图:
这里需要注意的一些地方是:
1、只有设置了如下方法,才能使绘制的进度条两头是圆的
progressPaint.setStrokeCap(Paint.Cap.ROUND);//让画笔画出的线条是圆的
如果没有设置Paint的该属性,则绘出来的效果如下:
2、要注意Canvas的drawArc方法,该方法用于画一段圆弧,其构造方法中的RectF参数,指定了所画圆弧的外边缘区域,后面两个参数指定绘制的初始位置和绘制的角度,比如上例中,初始位置为270,则会从圆环的顶部开始绘制,角度为30的话,则会从顶部开始绘制30度,drawArc接下来的一个参数为boolean值,为true时会画出圆弧的中央部分,为false时则只绘制圆弧的边缘,drawArc的最后一个参数为画笔Paint对象,这里就不用多说了
下面上两张图用来说明drawArc方法:
上面图1对应的代码是:
RectF oval = new RectF(x - radius, y - radius, x + radius, y + radius);
canvas.drawArc(oval, 0, 90, false, paint);
图2对应的代码是:
RectF oval = new RectF(x - radius, y - radius, x + radius, y + radius);
canvas.drawArc(oval, 0, 90, true, paint);