当前位置: 移动技术网 > IT编程>移动开发>Android > Android自定义控件实现带数值和动画的圆形进度条

Android自定义控件实现带数值和动画的圆形进度条

2019年07月30日  | 移动技术网IT编程  | 我要评论

工笔荷花图片,阿拉德战记小说,娘子为夫饿了全文免费阅读

本文实例实现一个如下图所示的android自定义控件,可以直观地展示某个球队在某个赛季的积分数和胜场、负场、平局数

首先对画布进行区域划分,整个控件分上下两部分

上边是个大的圆环,圆环中间两行文字,没什么难度,选好圆心坐标和半径后直接绘制即可,绘制文字也是如此。

下部分是三个小的圆弧进度条,弧的末端绘制一个小的实心圆

首先选好坐标和半径,然后先绘制三个圆环作为弧形进度条的背景

之后从12点钟开始绘制进度弧,知道了圆环的圆心和半径,也知道了弧对应于12点钟和圆环圆心的偏移角度

通过三角函数可以计算出进度弧终点坐标,以进度弧终点坐标为圆心绘制一个小的实心圆即可

动画效果通过handler的postdelayed方法触发重绘即可实现

在项目中的效果如图所示:

测试代码如下:

final random random=new random();
final scoreboardview myview=(scoreboardview)findviewbyid(r.id.custom_view);
myview.setonclicklistener(new view.onclicklistener(){
 @override
 public void onclick(view v){
  myview.setcolor(color.blue);
  myview.setscore(random.nextint(28));
  myview.setwindrawlose(random.nextint(12),random.nextint(15),random.nextint(26));
 }
});

完整代码如下:

public class scoreboardview extends view {
 private context context;
 /*弧的颜色*/
 private int mcolor;
 /*积分数,胜场数,平局数,负场数*/
 private int mscore, mwinnumber, mdrawnumber, mlosenumber;
 /*传入数字的最大值*/
 private final int full_score = 30;
 /*动画插值器*/
 decelerateinterpolator mdecelerateinterpolator = new decelerateinterpolator();
 /*动画持续时间(刷新次数)*/
 private int mduration = 10;
 /*动画刷新过程中的当前值*/
 private int mcurrenttime = 0;
 private typedvalue typedvalue;
 private typedvalue typedvalue1;
 private handler mhandler = new handler();
 private runnable manimation = new runnable() {
  @override
  public void run() {
   if (mcurrenttime < mduration) {
    mcurrenttime++;
    /*导致重绘调用ondraw,ondraw最后再次postdelay执行此动画,直到达到指定的次数*/
    scoreboardview.this.invalidate();
   }
  }
 };
 /*绘制图形*/
 private paint paint = new paint();
 /*绘制文字*/
 private paint painttext = new paint();
 
 public scoreboardview(context context) {
  super(context);
  this.context=context;
  init();
 }
 
 public scoreboardview(context context, attributeset attrs) {
  super(context, attrs);
  this.context=context;
  init();
 }
 
 public scoreboardview(context context, attributeset attrs, int defstyleattr) {
  super(context, attrs, defstyleattr);
  this.context=context;
  init();
 }
 
 private void init() {
  /*数据初始化,默认属性*/
  mcolor = color.rgb(95, 112, 72);
  mscore = 0;
  mwinnumber = 0;
  mdrawnumber = 0;
  mlosenumber = 0;
  typedvalue=new typedvalue();
  typedvalue1=new typedvalue();
  context.gettheme().resolveattribute(r.attr.maintextclor, typedvalue, true);
  context.gettheme().resolveattribute(r.attr.maintextclor_reverse,typedvalue1,true);
 }
 
 @override
 protected void ondraw(canvas canvas) {
  super.ondraw(canvas);
  /*获取控件总的宽高*/
  float totalwidth = getwidth();
  float totalheight = getheight();
  /*
  * decelerateinterpolator:动画从开始到结束,变化率是一个减速的过程。
  * accelerateinterpolator:动画从开始到结束,变化率是一个加速的过程。
  * cycleinterpolator:动画从开始到结束,变化率是循环给定次数的正弦曲线
  * acceleratedecelerateinterpolator:动画从开始到结束,变化率是先加速后减速的过程。
  * linearinterpolator:动画从开始到结束,变化率是线性变化。
  * */
  /*计算当前时刻动画进度值*/
  float animcurrentvalue =mdecelerateinterpolator.getinterpolation(1.0f * mcurrenttime / mduration);
 
  /*图形画笔设置*/
  paint.setantialias(true);
  paint.setstyle(paint.style.stroke);
 
  /*积分数,上边的大圆*/
  paint.setstrokewidth(4);
  paint.setcolor(mcolor);
  /*积分大圆的中心坐标和半径*/
  float score_radius = totalheight * 1 / 5, score_circle_x = totalwidth / 2, score_circle_y = totalheight / 3;
  /*绘制圆弧*/
  canvas.drawcircle(score_circle_x, score_circle_y, score_radius, paint);
  /*文字画笔基本设置*/
  painttext.setantialias(true);
  painttext.setstyle(paint.style.stroke);
  /*文字从中间开始绘制*/
  /*paint.align.center:the text is drawn centered horizontally on the x,y origin*/
  painttext.settextalign(paint.align.center);
  /*文字画笔大小和颜色设置*/
  painttext.settextsize(score_radius * 3 / 4);
  painttext.setcolor(getresources().getcolor(typedvalue.resourceid));
  /*圆心位置绘制积分数值*/
  canvas.drawtext("" + mscore, score_circle_x, score_circle_y, painttext);
  /*缩小字体绘制文本信息*/
  painttext.settextsize(score_radius * 1 / 4);
  painttext.setalpha(80);
  /*圆心下边绘制文本*/
  canvas.drawtext("积分", score_circle_x, score_circle_y + score_radius / 2, painttext);
 
  /*设置画笔,画下边的三个小圆*/
  paint.setstrokewidth(4);
  paint.setalpha(255);
  /*下边三个小圆的半径*/
  float small_radius = totalheight / 10;
  /*三个小圆的圆心的x坐标*/
  float[] circlexs = new float[]{totalwidth / 2 - score_radius * 3 / 2,
          totalwidth / 2,
          totalwidth / 2 + score_radius * 3 / 2};
  /*三个小圆的圆心的y坐标*/
  float circley = totalheight * 3 / 4;
  /*计算三个小圆弧扫过的角度*/
  float[] theta_values = new float[]{360 * mwinnumber / full_score* animcurrentvalue,
           360 * mdrawnumber / full_score* animcurrentvalue,
           360 * mlosenumber / full_score* animcurrentvalue};
  /*设置画笔颜色,绘制外围圆环*/
  paint.setcolor(getresources().getcolor(typedvalue1.resourceid));
  /*分别绘制三个外围圆环*/
  canvas.drawcircle(circlexs[0], circley, small_radius, paint);//画win背景圆
  canvas.drawcircle(circlexs[1], circley, small_radius, paint);//画draw背景圆
  canvas.drawcircle(circlexs[2], circley, small_radius, paint);//画lose背景圆
  /*更改画笔颜色,绘制圆弧进度条*/
  paint.setcolor(mcolor);
  /*drawarc的起始角度是3点钟方向,因此要从12点钟方向开始绘制,起始角度为270度*/
  canvas.drawarc(new rectf(circlexs[0] - small_radius,
         circley - small_radius,
         circlexs[0] + small_radius,
         circley + small_radius),
      270, theta_values[0], false, paint);//画win圆形进度条
  canvas.drawarc(new rectf(circlexs[1] - small_radius,
         circley - small_radius,
         circlexs[1] + small_radius,
         circley + small_radius),
      270, theta_values[1], false, paint);//画draw圆形进度条
  canvas.drawarc(new rectf(circlexs[2] - small_radius,
         circley - small_radius,
         circlexs[2] + small_radius,
         circley + small_radius),
      270, theta_values[2], false, paint);//画lose圆形进度条
  /*绘制圆弧结束处的小圆点,实心圆*/
  paint.setstyle(paint.style.fill);
  /*已知半径、圆心位置、便宜角度,根据三角函数很方便计算出小实心圆圆心坐标*/
  canvas.drawcircle(circlexs[0] + small_radius * (float) math.sin(theta_values[0] * math.pi / 180),
    circley - small_radius * (float) math.cos(theta_values[0] * math.pi / 180), 6, paint);//画win末尾小圆点
  canvas.drawcircle(circlexs[1] + small_radius * (float) math.sin(theta_values[1] * math.pi / 180),
    circley - small_radius * (float) math.cos(theta_values[1] * math.pi / 180), 6, paint);//画draw末尾小圆点
  canvas.drawcircle(circlexs[2] + small_radius * (float) math.sin(theta_values[2] * math.pi / 180),
    circley - small_radius * (float) math.cos(theta_values[2] * math.pi / 180), 6, paint);//画lose末尾小圆点
 
  /*绘制文字*/
  painttext.setcolor(getresources().getcolor(typedvalue.resourceid));
  painttext.settextsize(small_radius * 2 / 3);
  /*测量文字大小,确定绘制文字时垂直方向的位置*/
  paint.fontmetrics fontmetrics = paint.getfontmetrics();
  float textbaselineoffset = (fontmetrics.bottom - fontmetrics.top) / 2 - fontmetrics.bottom;
  /*在三个小圆的正中心位置绘制相应的数字*/
  canvas.drawtext("" + (int)(mwinnumber * animcurrentvalue), circlexs[0], circley + textbaselineoffset, painttext);
  canvas.drawtext("" + (int)(mdrawnumber * animcurrentvalue), circlexs[1], circley + textbaselineoffset, painttext);
  canvas.drawtext("" + (int)(mlosenumber * animcurrentvalue), circlexs[2], circley + textbaselineoffset, painttext);
  /*调整字体大小,绘制文本信息*/
  painttext.settextsize(small_radius * 4 / 9);
  canvas.drawtext("胜场", circlexs[0], circley - small_radius*4/3, painttext);
  canvas.drawtext("平局", circlexs[1], circley - small_radius*4/3, painttext);
  canvas.drawtext("负场", circlexs[2], circley - small_radius*4/3, painttext);
  /*20ms刷新一次数据*/
  mhandler.postdelayed(manimation, 20);//启动动画
 }
 
 public void setcolor(int mcolor) {
  this.mcolor = mcolor;
  invalidate();
 }
 
 public void setscore(int score) {
  this.mscore = score;
  invalidate();
 }
 
 public void setwindrawlose(int win,int draw,int lose) {
  this.mwinnumber = win;
  this.mdrawnumber = draw;
  this.mlosenumber = lose;
  mcurrenttime =0;
  invalidate();
 }
}

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

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网