自定义圆形进度View

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();

}

});

}

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容