Android编程基于自定义View实现绚丽的圆形进度条功能示例
程序员文章站
2024-02-13 15:38:58
本文实例讲述了android编程基于自定义view实现绚丽的圆形进度条功能。分享给大家供大家参考,具体如下:
本文包含两个组件,首先上效果图:
1.progressba...
本文实例讲述了android编程基于自定义view实现绚丽的圆形进度条功能。分享给大家供大家参考,具体如下:
本文包含两个组件,首先上效果图:
1.progressbarview1(支持拖动):
2.progressbarview2(不同进度值显示不同颜色,不支持拖拽):
代码不多,注释也比较详细,全部贴上了:
(一)progressbarview1:
/** * 自定义绚丽的progressbar. */ public class progressbarview1 extends view { /** * 进度条所占用的角度 */ private static final int arc_full_degree = 300; /** * 弧线的宽度 */ private int stroke_width; /** * 组件的宽,高 */ private int width, height; /** * 进度条最大值和当前进度值 */ private float max, progress; /** * 是否允许拖动进度条 */ private boolean draggingenabled = false; /** * 绘制弧线的矩形区域 */ private rectf circlerectf; /** * 绘制弧线的画笔 */ private paint progresspaint; /** * 绘制文字的画笔 */ private paint textpaint; /** * 绘制当前进度值的画笔 */ private paint thumbpaint; /** * 圆弧的半径 */ private int circleradius; /** * 圆弧圆心位置 */ private int centerx, centery; public progressbarview1(context context) { super(context); init(); } public progressbarview1(context context, attributeset attrs) { super(context, attrs); init(); } public progressbarview1(context context, attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); init(); } private void init() { progresspaint = new paint(); progresspaint.setantialias(true); textpaint = new paint(); textpaint.setcolor(color.white); textpaint.setantialias(true); thumbpaint = new paint(); thumbpaint.setantialias(true); //使用自定义字体 textpaint.settypeface(typeface.createfromasset(getcontext().getassets(), "fangz.ttf")); } @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { super.onmeasure(widthmeasurespec, heightmeasurespec); if (width == 0 || height == 0) { width = getwidth(); height = getheight(); //计算圆弧半径和圆心点 circleradius = math.min(width, height) / 2; stroke_width = circleradius / 12; circleradius -= stroke_width; centerx = width / 2; centery = height / 2; //圆弧所在矩形区域 circlerectf = new rectf(); circlerectf.left = centerx - circleradius; circlerectf.top = centery - circleradius; circlerectf.right = centerx + circleradius; circlerectf.bottom = centery + circleradius; } } private rect textbounds = new rect(); @override protected void ondraw(canvas canvas) { super.ondraw(canvas); float start = 90 + ((360 - arc_full_degree) >> 1); //进度条起始点 float sweep1 = arc_full_degree * (progress / max); //进度划过的角度 float sweep2 = arc_full_degree - sweep1; //剩余的角度 //绘制起始位置小圆形 progresspaint.setcolor(color.white); progresspaint.setstrokewidth(0); progresspaint.setstyle(paint.style.fill); float radians = (float) (((360.0f - arc_full_degree) / 2) / 180 * math.pi); float startx = centerx - circleradius * (float) math.sin(radians); float starty = centery + circleradius * (float) math.cos(radians); canvas.drawcircle(startx, starty, stroke_width / 2, progresspaint); //绘制进度条 progresspaint.setstrokewidth(stroke_width); progresspaint.setstyle(paint.style.stroke);//设置空心 canvas.drawarc(circlerectf, start, sweep1, false, progresspaint); //绘制进度条背景 progresspaint.setcolor(color.parsecolor("#d64444")); canvas.drawarc(circlerectf, start + sweep1, sweep2, false, progresspaint); //绘制结束位置小圆形 progresspaint.setstrokewidth(0); progresspaint.setstyle(paint.style.fill); float endx = centerx + circleradius * (float) math.sin(radians); float endy = centery + circleradius * (float) math.cos(radians); canvas.drawcircle(endx, endy, stroke_width / 2, progresspaint); //上一行文字 textpaint.settextsize(circleradius >> 1); string text = (int) (100 * progress / max) + ""; float textlen = textpaint.measuretext(text); //计算文字高度 textpaint.gettextbounds("8", 0, 1, textbounds); float h1 = textbounds.height(); //% 前面的数字水平居中,适当调整 float extra = text.startswith("1") ? -textpaint.measuretext("1") / 2 : 0; canvas.drawtext(text, centerx - textlen / 2 + extra, centery - 30 + h1 / 2, textpaint); //百分号 textpaint.settextsize(circleradius >> 2); canvas.drawtext("%", centerx + textlen / 2 + extra + 5, centery - 30 + h1 / 2, textpaint); //下一行文字 textpaint.settextsize(circleradius / 5); text = "可用内存充足"; textlen = textpaint.measuretext(text); textpaint.gettextbounds(text, 0, text.length(), textbounds); float h2 = textbounds.height(); canvas.drawtext(text, centerx - textlen / 2, centery + h1 / 2 + h2, textpaint); //绘制进度位置,也可以直接替换成一张图片 float progressradians = (float) (((360.0f - arc_full_degree) / 2 + sweep1) / 180 * math.pi); float thumbx = centerx - circleradius * (float) math.sin(progressradians); float thumby = centery + circleradius * (float) math.cos(progressradians); thumbpaint.setcolor(color.parsecolor("#33d64444")); canvas.drawcircle(thumbx, thumby, stroke_width * 2.0f, thumbpaint); thumbpaint.setcolor(color.parsecolor("#99d64444")); canvas.drawcircle(thumbx, thumby, stroke_width * 1.4f, thumbpaint); thumbpaint.setcolor(color.white); canvas.drawcircle(thumbx, thumby, stroke_width * 0.8f, thumbpaint); } private boolean isdragging = false; @override public boolean ontouchevent(@nonnull motionevent event) { if (!draggingenabled) { return super.ontouchevent(event); } //处理拖动事件 float currentx = event.getx(); float currenty = event.gety(); int action = event.getaction(); switch (action) { case motionevent.action_down: //判断是否在进度条thumb位置 if (checkonarc(currentx, currenty)) { float newprogress = caldegreebyposition(currentx, currenty) / arc_full_degree * max; setprogresssync(newprogress); isdragging = true; } break; case motionevent.action_move: if (isdragging) { //判断拖动时是否移出去了 if (checkonarc(currentx, currenty)) { setprogresssync(caldegreebyposition(currentx, currenty) / arc_full_degree * max); } else { isdragging = false; } } break; case motionevent.action_up: isdragging = false; break; } return true; } private float caldistance(float x1, float y1, float x2, float y2) { return (float) math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); } /** * 判断该点是否在弧线上(附近) */ private boolean checkonarc(float currentx, float currenty) { float distance = caldistance(currentx, currenty, centerx, centery); float degree = caldegreebyposition(currentx, currenty); return distance > circleradius - stroke_width * 5 && distance < circleradius + stroke_width * 5 && (degree >= -8 && degree <= arc_full_degree + 8); } /** * 根据当前位置,计算出进度条已经转过的角度。 */ private float caldegreebyposition(float currentx, float currenty) { float a1 = (float) (math.atan(1.0f * (centerx - currentx) / (currenty - centery)) / math.pi * 180); if (currenty < centery) { a1 += 180; } else if (currenty > centery && currentx > centerx) { a1 += 360; } return a1 - (360 - arc_full_degree) / 2; } public void setmax(int max) { this.max = max; invalidate(); } public void setprogress(float progress) { final float validprogress = checkprogress(progress); //动画切换进度值 new thread(new runnable() { @override public void run() { float oldprogress = progressbarview1.this.progress; for (int i = 1; i <= 100; i++) { progressbarview1.this.progress = oldprogress + (validprogress - oldprogress) * (1.0f * i / 100); postinvalidate(); systemclock.sleep(20); } } }).start(); } public void setprogresssync(float progress) { this.progress = checkprogress(progress); invalidate(); } //保证progress的值位于[0,max] private float checkprogress(float progress) { if (progress < 0) { return 0; } return progress > max ? max : progress; } public void setdraggingenabled(boolean draggingenabled) { this.draggingenabled = draggingenabled; } }
(二)progressbarview2:
/** * 自定义绚丽的progressbar. */ public class progressbarview2 extends view { /** * 进度条所占用的角度 */ private static final int arc_full_degree = 300; //进度条个数 private static final int count = 100; //每个进度条所占用角度 private static final float arc_each_progress = arc_full_degree * 1.0f / (count - 1); /** * 弧线细线条的长度 */ private int arc_line_length; /** * 弧线细线条的宽度 */ private int arc_line_width; /** * 组件的宽,高 */ private int width, height; /** * 进度条最大值和当前进度值 */ private float max, progress; /** * 绘制弧线的画笔 */ private paint progresspaint; /** * 绘制文字的画笔 */ private paint textpaint; /** * 绘制文字背景圆形的画笔 */ private paint textbgpaint; /** * 圆弧的半径 */ private int circleradius; /** * 圆弧圆心位置 */ private int centerx, centery; public progressbarview2(context context) { super(context); init(); } public progressbarview2(context context, attributeset attrs) { super(context, attrs); init(); } public progressbarview2(context context, attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); init(); } private void init() { progresspaint = new paint(); progresspaint.setantialias(true); textpaint = new paint(); textpaint.setcolor(color.white); textpaint.setantialias(true); textbgpaint = new paint(); textbgpaint.setantialias(true); } @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { super.onmeasure(widthmeasurespec, heightmeasurespec); if (width == 0 || height == 0) { width = getwidth(); height = getheight(); //计算圆弧半径和圆心点 circleradius = math.min(width, height) / 2; arc_line_length = circleradius / 6; arc_line_width = arc_line_length / 8; centerx = width / 2; centery = height / 2; } } private rect textbounds = new rect(); @override protected void ondraw(canvas canvas) { super.ondraw(canvas); float start = (360 - arc_full_degree) >> 1; //进度条起始角度 float sweep1 = arc_full_degree * (progress / max); //进度划过的角度 //绘制进度条 progresspaint.setcolor(color.parsecolor(calcolor(progress / max, "#ffff0000", "#ff00ff00"))); progresspaint.setstrokewidth(arc_line_width); float drawdegree = 1.6f; while (drawdegree <= arc_full_degree) { double a = (start + drawdegree) / 180 * math.pi; float linestartx = centerx - circleradius * (float) math.sin(a); float linestarty = centery + circleradius * (float) math.cos(a); float linestopx = linestartx + arc_line_length * (float) math.sin(a); float linestopy = linestarty - arc_line_length * (float) math.cos(a); if (drawdegree > sweep1) { //绘制进度条背景 progresspaint.setcolor(color.parsecolor("#88aaaaaa")); progresspaint.setstrokewidth(arc_line_width >> 1); } canvas.drawline(linestartx, linestarty, linestopx, linestopy, progresspaint); drawdegree += arc_each_progress; } //绘制文字背景圆形 textbgpaint.setstyle(paint.style.fill);//设置填充 textbgpaint.setcolor(color.parsecolor("#41668b")); canvas.drawcircle(centerx, centery, (circleradius - arc_line_length) * 0.8f, textbgpaint); textbgpaint.setstyle(paint.style.stroke);//设置空心 textbgpaint.setstrokewidth(2); textbgpaint.setcolor(color.parsecolor("#aaaaaaaa")); canvas.drawcircle(centerx, centery, (circleradius - arc_line_length) * 0.8f, textbgpaint); //上一行文字 textpaint.settextsize(circleradius >> 1); string text = (int) (100 * progress / max) + ""; float textlen = textpaint.measuretext(text); //计算文字高度 textpaint.gettextbounds("8", 0, 1, textbounds); float h1 = textbounds.height(); canvas.drawtext(text, centerx - textlen / 2, centery - circleradius / 10 + h1 / 2, textpaint); //分 textpaint.settextsize(circleradius >> 3); textpaint.gettextbounds("分", 0, 1, textbounds); float h11 = textbounds.height(); canvas.drawtext("分", centerx + textlen / 2 + 5, centery - circleradius / 10 + h1 / 2 - (h1 - h11), textpaint); //下一行文字 textpaint.settextsize(circleradius / 6); text = "点击优化"; textlen = textpaint.measuretext(text); canvas.drawtext(text, centerx - textlen / 2, centery + circleradius / 2.5f, textpaint); } public void setmax(int max) { this.max = max; invalidate(); } //动画切换进度值(异步) public void setprogress(final float progress) { new thread(new runnable() { @override public void run() { float oldprogress = progressbarview2.this.progress; for (int i = 1; i <= 100; i++) { progressbarview2.this.progress = oldprogress + (progress - oldprogress) * (1.0f * i / 100); postinvalidate(); systemclock.sleep(20); } } }).start(); } //直接设置进度值(同步) public void setprogresssync(float progress) { this.progress = progress; invalidate(); } /** * 计算渐变效果中间的某个颜色值。 * 仅支持 #aarrggbb 模式,例如 #ccc9c9b2 */ public string calcolor(float fraction, string startvalue, string endvalue) { int start_a, start_r, start_g, start_b; int end_a, end_r, end_g, end_b; //start start_a = getintvalue(startvalue, 1, 3); start_r = getintvalue(startvalue, 3, 5); start_g = getintvalue(startvalue, 5, 7); start_b = getintvalue(startvalue, 7, 9); //end end_a = getintvalue(endvalue, 1, 3); end_r = getintvalue(endvalue, 3, 5); end_g = getintvalue(endvalue, 5, 7); end_b = getintvalue(endvalue, 7, 9); return "#" + gethexstring((int) (start_a + fraction * (end_a - start_a))) + gethexstring((int) (start_r + fraction * (end_r - start_r))) + gethexstring((int) (start_g + fraction * (end_g - start_g))) + gethexstring((int) (start_b + fraction * (end_b - start_b))); } //从原始#aarrggbb颜色值中指定位置截取,并转为int. private int getintvalue(string hexvalue, int start, int end) { return integer.parseint(hexvalue.substring(start, end), 16); } private string gethexstring(int value) { string a = integer.tohexstring(value); if (a.length() == 1) { a = "0" + a; } return a; } }
更多关于android相关内容感兴趣的读者可查看本站专题:《android视图view技巧总结》、《android开发动画技巧汇总》、《android编程之activity操作技巧总结》、《android布局layout技巧总结》、《android开发入门与进阶教程》、《android资源操作技巧汇总》及《android控件用法总结》
希望本文所述对大家android程序设计有所帮助。