packagecom.andbase.elememe.widget;
importandroid.content.Context;
importandroid.content.res.TypedArray;
importandroid.graphics.Canvas;
importandroid.graphics.Color;
importandroid.graphics.Paint;
importandroid.graphics.Rect;
importandroid.graphics.RectF;
importandroid.graphics.Typeface;
importandroid.util.AttributeSet;
importandroid.util.Log;
importandroid.view.View;
importcom.andbase.elememe.R;
/**
* Created by Administrator on 2016/12/22.
*/
public classRoundViewextendsView {
private static finalStringTAG="RoundView";
//圆的颜色
private introundColor;
//当前进度
private intprogress;
//进度条的颜色
private introundProgressColor;
//进度条的宽度
private floatroundWidth;
//中间文字的颜色
private inttextColor;
//中间文字的大小
private floattextSize;
//进度条的最大值
private intmax;
//是否显示文字
private booleantextIsDisplayable;
//画圆的风格
private intstyle;
//实心和空心的常量定义出来
public static final intSTORKE=0;
public static final intFILL=1;
//画笔
privatePaintmPaint;
publicRoundView(Context context) {
super(context);
}
publicRoundView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
/**
*对attrs中自定义的属性值的获取
*
*@paramcontext上下文环境
*@paramattrs系统会获得attrs文件中的自定义的属性
*/
private voidinit(Context context, AttributeSet attrs) {
//先初始化画笔
mPaint=newPaint();
//初始化typedArray用来获得自定义的属性值
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundView);
//获得圆的颜色,如果在XML文件中没有指定颜色,则用默认的颜色为BLUE蓝色
roundColor= typedArray.getColor(R.styleable.RoundView_roundColor, Color.BLUE);
//获得圆的进度的颜色,如果在XML文件中没有指定颜色,则用默认的颜色为BLACK黑色
roundProgressColor= typedArray.getColor(R.styleable.RoundView_roundProgressColor, Color.BLACK);
//获得进度条的宽度,如果在XML文件中没有指定宽度,则使用默认值10的宽度
roundWidth= typedArray.getDimension(R.styleable.RoundView_roundWidth,10);
//获得文字的颜色,如果没有指定,用默认红色
textColor= typedArray.getColor(R.styleable.RoundView_textColor, Color.RED);
//获得文字是否显示,如没有指定,默认FALSE;
textIsDisplayable= typedArray.getBoolean(R.styleable.RoundView_textIsDisplayable,false);
//获得文字大小,如没有指定,默认15大小
textSize= typedArray.getDimension(R.styleable.RoundView_textSize,16);
//获得进度的最大值,如没有指定,默认100
max= typedArray.getInt(R.styleable.RoundView_max,100);
//获得为实心圆还是空心圆,如没有指定,默认空心
style= typedArray.getInt(R.styleable.RoundView_style,0);
//个人理解为就像是listView的复写convertView一样,如果有了typedarray对象之后,调用此方法来重复使用.
typedArray.recycle();
}
@Override
protected voidonMeasure(intwidthMeasureSpec,intheightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected voidonDraw(Canvas canvas) {
super.onDraw(canvas);
/**画最外层的圆环
* 1,getWidth()方法获得的是目前这个View在设定好布局之后整个自身的宽度.
* getHeight()也是同样的道理.
* 2,获得centre为圆心的X轴坐标,半径是centre减去圆环的宽度除以2.
*在画一个圆的时候会有一个外边圆的宽度,此宽度除以2之后是此宽度的中心,
*当然在绘制的过程中,比如说圆环的宽度为10,那么开始绘制时是在10/2为5的半径处绘制的
* 3,底下的就很简单了,就是对画笔的设置而已.
*/
intcentre = getWidth() /2;
intradius = (int) (centre -roundWidth/2);//圆环的半径
mPaint.setColor(roundColor);//设置圆环的颜色
mPaint.setStyle(Paint.Style.STROKE);//设置空心
mPaint.setStrokeWidth(roundWidth);//设置圆环的宽度
mPaint.setAntiAlias(true);//消除锯齿
canvas.drawCircle(centre, centre, radius,mPaint);//画出圆环
Log.e("log", centre +"");
/**画进度的百分比
* setStrokeWidth()值>0的话,会比较粗,设置为0是字的原始粗细
* setTypeface()设置字体,此处设置为加粗字体,属性有五个属性值,可随意挑选
* percent百分比,计算出当前进度和总进度也就是max的百分比值.
* textWidth用画笔去测量measureText传入要绘制的文字
* drawText()方法的三个参数
*第一个是要绘制的文本
*第二个是文本的X轴坐标: centre是中心点,减去文本的宽度除以2,是文本的最左边,从最左边开始
*第三个是文本的Y轴坐标: centre是中心点,加上本的高度textsize除以2,是文本的最上边,从最上边开始
*绘制啦...
*/
mPaint.setStrokeWidth(0);
mPaint.setColor(textColor);
mPaint.setTextSize(textSize);
mPaint.setTypeface(Typeface.DEFAULT_BOLD);
intpercent = (int) ((float)progress/ (float)max*100);
floattextWidth =mPaint.measureText(percent +"%");
if(textIsDisplayable&& percent !=0&&style==STORKE) {
canvas.drawText(percent +"%", centre - textWidth /2, centre +textSize/2,mPaint);
}
/**
*画圆弧或者圆环的进度
* RectF对象是依据坐标的左上右下四个坐标点来绘制出一个矩形
*四个点为最左边的圆环的中心点,最上边的圆环的中心点,最右边的圆环的中心点,最下边的圆环的中心点.
*以这四个点构建了一个矩形.
*如果是空心圆进度的话,drawArc()方法有五个参数
*第一个是指定圆弧的外轮廓矩形区域.
*第二个是圆弧的起始角度,单位为度.为0度的时候是在圆环的最右边开始,我们从圆环上边开始,所以读书为270
*第三个是圆弧扫过的角度,单位为度,比如当前进度为50%,所以乘以360需要走180度,顺时针走.
*第四个是布尔值,如果为TRUE的话,绘制圆弧时将圆心包括在内,平时用来画扇形.故此处空心为TRUE,实心为FALSE.
*第五个是画笔..
*/
mPaint.setStrokeWidth(roundWidth);
mPaint.setColor(roundProgressColor);
RectF oval =newRectF(centre - radius, centre - radius, centre
+ radius, centre + radius);
switch(style){
caseSTORKE: {
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeCap(Paint.Cap.ROUND);
canvas.drawArc(oval,270,360*progress/max,false,mPaint);
break;
}
caseFILL: {
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
if(progress!=0)
canvas.drawArc(oval,270,360*progress/max,true,mPaint);//根据进度画圆弧
break;
}
}
}
/**
* get方法,同步获得max的值
*@return
*/
public synchronized intgetMax(){
returnmax;
}
/**
* set方法,同步设置max的值,如果进度<0的话,抛出非法参数异常.max必须大于0;
*@parammax
*/
public synchronized voidsetMax(intmax){
if(max <0){
throw newIllegalArgumentException("max must be greater than 0 ");
}
this.max= max;
}
/**
*设置当前的进度,由于多线程,需要同步,刷新界面调用POSTInvalidate在非UI线程刷新.
*@paramprogress
*/
public synchronized voidsetProgress(intprogress){
if(progress <0){
throw newIllegalArgumentException("progress must be greater than 0 ");
}
if(progress >max){
progress =max;
}
if(progress <=max){
this.progress= progress;
postInvalidate();
}
}
public intgetCricleColor() {
returnroundColor;
}
public voidsetCricleColor(intcricleColor) {
this.roundColor= cricleColor;
}
public intgetCricleProgressColor() {
returnroundProgressColor;
}
public voidsetCricleProgressColor(intcricleProgressColor) {
this.roundProgressColor= cricleProgressColor;
}
public intgetTextColor() {
returntextColor;
}
public voidsetTextColor(inttextColor) {
this.textColor= textColor;
}
public floatgetTextSize() {
returntextSize;
}
public voidsetTextSize(floattextSize) {
this.textSize= textSize;
}
public floatgetRoundWidth() {
returnroundWidth;
}
public voidsetRoundWidth(floatroundWidth) {
this.roundWidth= roundWidth;
}
}
感谢http://blog.csdn.net/xiaanming/article/details/10298163
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
android:id="@+id/roundView"
android:layout_width="200dp"
android:layout_height="200dp"
app:roundColor="@color/colorAccent"
app:roundProgressColor="@color/colorPrimary"
app:roundWidth="10dp"
app:style="STROKE"
app:textColor="@color/colorPrimaryDark"
app:textIsDisplayable="true"
app:textSize="26sp"
app:max="100"
/>
android:id="@+id/bt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="100dp"
android:text="start"
/>
packagecom.andbase.elememe;
importandroid.os.Bundle;
importandroid.os.Handler;
importandroid.os.Message;
importandroid.support.annotation.Nullable;
importandroid.support.v7.app.AppCompatActivity;
importandroid.view.View;
importandroid.widget.Button;
importcom.andbase.elememe.widget.RoundView;
/**
* Created by Administrator on 2016/12/22.
*/
public classMainActivityextendsAppCompatActivity {
privateRoundViewmRoundView;
privateHandlermHandler=newHandler(){
@Override
public voidhandleMessage(Message msg) {
super.handleMessage(msg);
if(msg.what==1){
mRoundView.setProgress(progress);
mRoundView.invalidate();
}
}
};
private intprogress=0;
privateButtonmButton;
@Override
protected voidonCreate(@NullableBundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test);
mRoundView= (RoundView) findViewById(R.id.roundView);
mButton= (Button) findViewById(R.id.bt);
mButton.setOnClickListener(newView.OnClickListener() {
@Override
public voidonClick(View view) {
newThread(newRunnable() {
@Override
public voidrun() {
while(true) {
try{
Thread.sleep(100);
progress++;
mHandler.sendEmptyMessage(1);
if(progress>=100) {
break;
}
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
});
}
}