欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android自定义控件实现带文本与数字的圆形进度条

程序员文章站 2022-08-20 16:09:16
本文实例为大家分享了android实现圆形进度条的具体代码,供大家参考,具体内容如下 实现的效果图如下所示: 第一步:绘制下方有缺口的空心圆,称为外围大弧吧...

本文实例为大家分享了android实现圆形进度条的具体代码,供大家参考,具体内容如下

实现的效果图如下所示:

Android自定义控件实现带文本与数字的圆形进度条

Android自定义控件实现带文本与数字的圆形进度条

第一步:绘制下方有缺口的空心圆,称为外围大弧吧

anvas.cliprect(0, 0, mwidth, mheight / 2 + radius - textheight * 3 / 4);

第二步:计算绘制圆弧进度条时的起始角度,设置为外围大弧的左端点为进度值得起点,扫过的角度所占外围大弧的百分比就是进度值

第三步:绘制数字、文字、百分号

第四步:使用handler runnable 和decelerateinterpolator是进度条和数字动起来

测试代码:

final customcirclebar circle=(customcirclebar)findviewbyid(r.id.win_home);
circle.setpercent(10);
circle.setcustomtext("呵呵");
circle.setprogesscolor(getresources().getcolor(r.color.blue));
final random random=new random();
circle.setonclicklistener(new view.onclicklistener(){
 @override
 public void onclick(view v){
 circle.setpercent(random.nextint(100));
 }
});

完成代码如下:

public class customcirclebar extends view {
 private context context;
 /**
 * 进度值
 */
 private int percent;
 /**
 * 颜色值
 */
 private int mprogesscolor;
 /**
 * 下边的文字名称
 */
 private string mcustomtext;
 /**
 * 外圈圆环的画笔
 */
 private paint paintbar = new paint();
 /**
 * 下边文字的画笔
 */
 private paint painttext = new paint();
 /**
 * 动态获取属性值
 */
 private typedvalue typedvalue;
 /**
 * 先加速后减速
 */
 decelerateinterpolator mdecelerateinterpolator = new decelerateinterpolator();
 /**
 * 动画持续时间
 */
 private int duration = 10;
 private int curtime = 0;
 public customcirclebar(context context) {
 super(context);
 this.context=context;
 init();
 }
 
 public customcirclebar(context context, attributeset attrs) {
 super(context, attrs);
 this.context=context;
 init();
 }
 
 public customcirclebar(context context, attributeset attrs, int defstyleattr) {
 super(context, attrs, defstyleattr);
 this.context=context;
 init();
 }
 
 
 
 public void setpercent(int percent) {
 this.percent = percent;
 /*isshown():returns the visibility of this view and all of its ancestors*/
 if (isshown()) {
  /**
  * 设置进度后重新开始一次动画
  */
  curtime=0;
  this.invalidate();
 }
 }
 
 public void setprogesscolor(int mprogesscolor) {
 this.mprogesscolor = mprogesscolor;
 if (isshown()) {
  this.invalidate();
 }
 }
 
 
 public void setcustomtext(string mcustomtext) {
 this.mcustomtext = mcustomtext;
 }
 
 private handler mhandler = new handler();
 private runnable manimation = new runnable() {
 @override
 public void run() {
  if (curtime < duration) {
  curtime++;
  /** 导致重绘,调用ondraw,ondraw最后调用
   * mhandler.postdelayed(manimation, 20);更新进度条,界面重绘
   * 每次20毫秒,绘制10次,因此动画时间200毫秒
   */
  customcirclebar.this.invalidate();
  }
 }
 };
 
 private void init() {
 /**
  * 数据初始化,没有设置属性时候的默认值
  */
 percent = 0;
 mprogesscolor=color.rgb(95,112,72);
 mcustomtext="home";
 typedvalue=new typedvalue();
 context.gettheme().resolveattribute(r.attr.maintextclor,typedvalue,true);
 }
 
 
 
 @override
 protected void ondraw(canvas canvas) {
 super.ondraw(canvas);
 float mwidth = getwidth();
 float mheight = getheight();
 /**
  * 下边是进度条画笔的设置
  */
 /** restores the paint to its default settings. */
 paintbar.reset();
 /**
  * 圆环宽度4个像素
  */
 paintbar.setstrokewidth(4);
 /**
  * 空心圆环而非填充的额扇形
  */
 paintbar.setstyle(paint.style.stroke);
 paintbar.setantialias(true);
 paintbar.setcolor(mprogesscolor);
 /**
  * 调整下不透明度,使边框弧和进度条区分开
  */
 paintbar.setalpha(80);
 /**
  * 接下来是文字画笔的设置
  */
 painttext.settextsize(20);
 painttext.setcolor(getresources().getcolor(typedvalue.resourceid));
 painttext.setstyle(paint.style.stroke);
 painttext.setantialias(true);
 /**
  * 从中间开始绘制文本
  */
 painttext.settextalign(paint.align.center);
 /**
  * 测量文字大小
  */
 paint.fontmetrics fontmetrics = painttext.getfontmetrics();
 /**
  * 计算文字高度
  */
 float textheight = fontmetrics.bottom - fontmetrics.top;
 /**
  * 计算圆的半径
  */
 float radius = math.min(mwidth, mheight) / 2 - 10;
 /* ❑ save:用来保存canvas的状态。save之后,可以调用canvas的平移、放缩、旋转、错切、裁剪等操作。
  ❑ restore:用来恢复canvas之前保存的状态。防止save后对canvas执行的操作对后续的绘制有影响。*/
 /*保存画布,绘制进度条*/
 canvas.save();
 /*cliprect:该方法用于裁剪画布,也就是设置画布的显示区域
 调用cliprect()方法后,只会显示被裁剪的区域,之外的区域将不会显示 */
 canvas.cliprect(0, 0, mwidth, mheight / 2 + radius - textheight * 3 / 4);
 /*因为cliprect的原因,外边的圆环下边留个缺口绘制文字*/
 canvas.drawcircle(mwidth / 2, mheight / 2, radius, paintbar);
 
 /**
  * 三角函数计算,下方缺口扇形的角度的一半
  */
 float theta_offset = (float) math.acos((radius - textheight / 2) / radius);
 /**
  * 大弧围成的扇形的角度
  */
 float theta_full = 360 - 2 * theta_offset;
 /**
  * 进度值围成的弧对应的角度
  */
 float thetaprocess = mdecelerateinterpolator.getinterpolation(1.0f * curtime / duration) * percent * theta_full / 100;
 /**
  * 设置进度值颜色完全不透明
  */
 paintbar.setalpha(255);
 paintbar.setcolor(mprogesscolor);
 /**
  * 注意弧形的起始角度,下边因显示文字导致圆环断开成一条弧,弧有左右两个端点,从左端点开始画弧
  */
 canvas.drawarc(new rectf(mwidth / 2 - radius, mheight / 2 - radius, mwidth / 2 + radius, mheight / 2 + radius), theta_offset+90, thetaprocess, false, paintbar);
 /**
  * 恢复画布
  */
 canvas.restore();
 /**
  * 开始绘制文字
  */
 painttext.settextsize(20);
 fontmetrics = painttext.getfontmetrics();
 float textbaselineoffset = (fontmetrics.bottom - fontmetrics.top) / 2 - fontmetrics.bottom;
 canvas.drawtext(mcustomtext, mwidth / 2, mheight / 2 + radius - textheight / 2 + textbaselineoffset, painttext);
 
 /**
  * 绘制百分号
  */
 painttext.settextsize(mheight * 1 / 8);
 fontmetrics = painttext.getfontmetrics();
 textbaselineoffset = (fontmetrics.bottom - fontmetrics.top) / 2 - fontmetrics.bottom;
 canvas.drawtext("%", mwidth / 2, mheight / 2 + radius / 3 + textbaselineoffset, painttext);
 
 /**
  * 绘制百分比
  */
 painttext.settextsize(mheight * 3 / 8);
 canvas.drawtext("" + (int)(percent*mdecelerateinterpolator.getinterpolation(1.0f * curtime / duration)), mwidth / 2, mheight / 2, painttext);
 /**
  * 20毫秒后执行动画
  */
 mhandler.postdelayed(manimation, 20);
 }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。