自定义圆形进度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();

}

});

}

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容