上周遇到一个需求, 用一个圆形进度条的形式来展示某项操作所占的比例, 虽然类似的轮子已经有很多了, 但是这种简单的自定义 View 个人觉得有时间的话, 还是自己写写比较好.
首先来看一下效果图:
分析: 从效果图可以看到, 这个效果整体分为以下几部分:
背景圆环
进度圆弧
终点小圆圈 (进度为 0 和进度为 100% 的时候应当没有)
内部三行文字
怎么实现: 分析出整体框架之后, 思路其实已经很简单了, 我是这样实现的:
画背景圆
按照当前进度计算出扫过的弧度来画一个圆弧
以第二步的圆弧结束位置为坐标, 画两个大小不同的实心圆, 达到设计效果
分别画三行文字
第三步中, 在确定圆弧终点位置的时候用到了三角函数, 这里简单画了一个图, 很好理解:
以顶点为起点, 圆半径为 r, 圆弧扫过的角度为α.
代码 简单列下主要代码, 完整代码地址放在了文字末尾. 1. 为了更加灵活, 我这里提供了很多属性用于用户自己来设置:
- private String title;
- private String num;
- private String unit;
- private float titleTextsize;
- private float numTextsize;
- private float unitTextsize;
- private int titleTextColor;
- private int numTextColor;
- private int unitTextColor;
- private float backCircleWidth;
- private float outerCircleWidth;
- private int backCircleColor;
- private int outerCircleColor;
- private float endCircleWidth;
- private int endCircleColor;
2. 为了代码更加清晰, 设置了如下 Paint
- private Paint backCirclePaint,// 画背景圆
- outerCirclePaint,// 画进度圆弧
- endCirclePaint,// 画终点实心大圆
- endCirclePaint2,// 画终点实心小圆
- titlePaint,// 画第一行文字
- numPaint,// 画第二行文字
- unitPaint;// 画第三行文字
3. 在 onDraw 方法中实现绘制操作
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- int centerX = width / 2;
- int centerY = height / 2;
- // 计算半径
- float radius = (width / 2) - outerCircleWidth + (outerCircleWidth - backCircleWidth) / 2;
- // 画背景圆
- canvas.drawCircle(centerX, centerY, radius, backCirclePaint);
- // 根据进度话扫过一定角度的圆弧
- RectF rectF = new RectF(outerCircleWidth / 2 + backCircleWidth / 2, outerCircleWidth / 2 + backCircleWidth / 2, width - outerCircleWidth / 2 - backCircleWidth / 2, height - outerCircleWidth / 2 - backCircleWidth / 2);
- canvas.drawArc(rectF, -90, 360 * currentPercent, false, outerCirclePaint);
- // 画三行文字
- Rect textRect = new Rect();
- titlePaint.getTextBounds(title, 0, title.length(), textRect);
- canvas.drawText(title, width / 2 - textRect.width() / 2, height / 4 + textRect.height() / 2, titlePaint);
- numPaint.getTextBounds(num, 0, num.length(), textRect);
- canvas.drawText(num, width / 2 - textRect.width() / 2, height / 2 + textRect.height() / 2, numPaint);
- unitPaint.getTextBounds(unit, 0, unit.length(), textRect);
- canvas.drawText(unit, width / 2 - textRect.width() / 2, height * 2 / 3 + textRect.height() / 2, unitPaint);
- // 我这里规定进度在 0~100% 的时候才会画终点小圆, 可以自由改动
- if (currentPercent <1 && currentPercent> 0) {
- canvas.drawCircle(centerX + rectF.width() / 2 * (float) Math.sin(360 * currentPercent * Math.PI / 180),
- centerY - rectF.width() / 2 * (float) Math.cos(360 * currentPercent * Math.PI / 180), endCircleWidth / 2, endCirclePaint);
- canvas.drawCircle(centerX + rectF.width() / 2 * (float) Math.sin(360 * currentPercent * Math.PI / 180),
- centerY - rectF.width() / 2 * (float) Math.cos(360 * currentPercent * Math.PI / 180), endCircleWidth / 4, endCirclePaint2);
- }
- }
完整代码地址 https://github.com/SolveBugs/BlogPracticeDems
切换到 progressviewwithcircle 这个 moudle 运行即可看到效果, 有兴趣的小伙伴可以看下, 希望大佬们有其他更好的实现方式.
来源: https://juejin.im/entry/5b8a17f9e51d4538b63d3a15