转载自:books1958   原文:https://blog.csdn.net/books1958/article/details/48267903

本博文包含两个组件,首先上效果图:

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"));}@Overrideprotected 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();@Overrideprotected 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;@Overridepublic 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() {@Overridepublic 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);}@Overrideprotected 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();@Overrideprotected 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() {@Overridepublic 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;//startstart_a = getIntValue(startValue, 1, 3);start_r = getIntValue(startValue, 3, 5);start_g = getIntValue(startValue, 5, 7);start_b = getIntValue(startValue, 7, 9);//endend_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:自定义View实现绚丽的圆形进度条相关推荐

  1. 精通Android自定义View(十二)绘制圆形进度条

    1 绘图基础简析 1 精通Android自定义View(一)View的绘制流程简述 2 精通Android自定义View(二)View绘制三部曲 3 精通Android自定义View(三)View绘制 ...

  2. android 自定义音乐圆形进度条,Android自定义View实现音频播放圆形进度条

    本篇文章介绍自定义View配合属性动画来实现如下的效果 实现思路如下: 根据播放按钮的图片大小计算出圆形进度条的大小 根据音频的时间长度计算出圆形进度条绘制的弧度 通过Handler刷新界面来更新圆形 ...

  3. Android 自定义View实现环形带刻度的进度条

    本篇文章讲的是自定义View实现环形带刻度的进度条.和往常一样,主要还是想总结一下自定义View实现环形带刻度的进度条的开发过程以及一些需要注意的地方. 按照惯例,我们先来看看效果图 一.我们如何来实 ...

  4. android+属性动画+高度,android 自定义view+属性动画实现充电进度条

    近期项目中需要使用到一种类似手机电池充电进度的动画效果,以前没学属性动画的时候,是用图片+定时器的方式来完成的,最近一直在学习动画这一块,再加上复习一下自定义view的相关知识点,所以打算用属性动画和 ...

  5. Android自定义没有资源文件的圆形进度条ProgressBar

    最近公司开发的SDK中需要使用圆形加载进度条,而且说要那种动态的转圈圈的那种进度条.当然这种进度条想实现很简单,用几个资源图片,以动画循环播放就行.但考虑到是SDK,有资源文件不好打包,想打包就要用到 ...

  6. 自定义View之王者荣耀等级进度条

    Demo效果 这里用王者荣耀的等级做了一个demo 实现思路 由进度条想到ProgressBar,继承自ProgressBar,可以在onDraw()中通过getProgress()和getMax() ...

  7. Android -- 自定义StepView实现个人信息验证进度条

    1,项目中要用到个人信息验证的在网上找了一下,好像有封装好了的StepView,首先感谢一下作者,这是作者的地址,效果图如下: 2,正准备撸起袖子就是一顿复制粘贴的时候,发现效果图成这个样子了(其实这 ...

  8. android 动态进度条,Android实用view系列------炫酷的进度条

    不知不觉距离上次写文章已经过去大半个月了,原本计划每周写一篇的想法在坚持几周之后最终还是被生活中各种各样的琐事打乱,无奈中夹杂这对自己的一点失望. 心痛.jpg 当初的愿望实现了吗 事到如今只好祭奠吗 ...

  9. 精通Android自定义View(十四)绘制水平向右加载的进度条

    1引言 1 精通Android自定义View(一)View的绘制流程简述 2 精通Android自定义View(二)View绘制三部曲 3 精通Android自定义View(三)View绘制三部曲综合 ...

  10. Android 自定义View实现环形带刻度颜色渐变的进度条

    上次写了一篇Android 自定义View实现环形带刻度的进度条,这篇文章就简单了,只是在原来的基础上加一个颜色渐变. 按照惯例,我们先来看看效果图 一.概述 1.相比于上篇文章,这里我们的颜色渐变主 ...

最新文章

  1. 说说项目从0-1过程中的那点事儿
  2. C#2.0 从sql server 中读取二进制图片
  3. htaccess 防止盗链,防止目录浏览等10大技巧
  4. 如何选择python书籍_如何选择一本优质的数据科学书籍
  5. 三角形周长和【牛客网】牛客网练习赛60
  6. 纪中C组模拟赛总结(2019.7.6)
  7. jquery-autocomplete学习(转)
  8. python语言输入两个数_python的函数输入两个参数吗
  9. phpcmsV9 完整更新ckeditor编辑器到最新版 - 源码篇
  10. 收获,不止SQL优化——抓住SQL的本质--第十章
  11. vue 保存时清空iuput_Vue 一键清空表单的实现方法
  12. 每日英语:Chinese Show Global Real-Estate Appetite
  13. Solr4.8.0源码分析(13)之LuceneCore的索引修复
  14. 我的CSDN博客下载器,下载博客文章保存为mht文件
  15. MT6763芯片资料MT6763处理器性能介绍下载
  16. 最新版MATLAB怎么运行代码,matlab怎么运行代码
  17. Java开发全终端实战租房项目——项目介绍以及开发后台系统
  18. erdas裁剪影像_ERDAS遥感图像的分幅裁剪
  19. 嵌入式平台ssh开发环境搭建
  20. 回收站的东西怎么恢复?mac电脑回收站清空还能恢复吗?

热门文章

  1. 方差、标准差、均方差、均方根值(RMS)、均方根误差(RMSE)
  2. Google Guava简介
  3. python操作 e'xcel表格
  4. 温度能够瞬间提升到千度以上?究竟是什么原理
  5. 攻防世界-Crypto-告诉你个秘密(键盘密码)-ISCC2017
  6. VirusTotal 为 Chrome 和 Firefox 发布 VT4Browsers 扩展
  7. linux下玩三国志游戏,三国志威力无双手游官网版
  8. java xml 小于等于_MyBatis中xml文件中的大于 大于等于 小于 小于等于 写法
  9. 软件配置管理中基线(baseline)
  10. 【电子DIY】基于NE555制作的简易电子琴