继承View基类,画了这样的扇形图

直接来步骤吧
(参考了GcsSloop的教程)
1.分析
自定义View需要认真的分析下,里面还是会用到一些数学知识
参数说明一下:
- oval :指定圆弧的外轮廓矩形区域
- startAngle: 圆弧起始角度,单位为度。
- sweepAngle: 圆弧扫过的角度,顺时针方向,单位为度。
- useCenter: 如果为True时,在绘制圆弧时将圆心包括在内,通常用来绘制扇形。
- paint: 绘制圆弧的画笔属性,如颜色,是否填充等。

1.1 分析需要哪些数据
参照上面的画圆弧函数的参数需求和上面那个结(cu)果(cao)图
要使用canvas画扇形需要这些参数吧
再看上面那个结(cu)果(cao)图,还需要
这样就可以定义一个数据结构了
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class ViewData { public String name; public int value;
public int color; public float percentage; public float angle;
public ViewData(int value, String name) { this.value = value; this.name = name; } }
|
1.2 角度计算
扇形图应该反应的是里面每块扇形占总数的百分比,在我们的数据结构里应该是通过数值(value)计算出扇形区域占总体的比例和扫过的角度
- 比例 = 数值 / 各块数值之和
- 角度 = 比例 x 圆周(360度)
1.3 文字位置确定
文字不像扇形区域可以直接调用画布的圆弧方法绘制,文字使用画布的drawText()方法
1 2 3
| public void drawText(@NonNull String text, float x, float y, @NonNull Paint paint) { ...... }
|
查看源码可知需要传递字符内容、x坐标、y坐标和画笔,字符内容和画笔容易,就是坐标位置我们要好好想想

需要注意这里的文字的位置坐标都是基于canvas为父元素的
回到以前的数学应用题,先摆出我们有哪些已知量

想想根据这些数据,应该可以求出文字位置(上图黑圆点)的坐标
- 文字位置角度 = 起始角度 + 扇形块角度/2
- 文字x坐标 = 半径/2 x cos(文字位置角度)
- 文字y坐标 = 半径/2 x sin(文字位置角度)
分析差不多了,开始实践了
2 实践
2.1 数据结构
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class ViewData { public String name; public int value;
public int color; public float percentage; public float angle;
public ViewData(int value, String name) { this.value = value; this.name = name; } }
|
2.2 View实现
先来一张图镇店

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
| public class MyView extends View { private int[] mColors = {Color.BLUE, Color.DKGRAY, Color.CYAN, Color.RED, Color.GREEN}; private Paint paint; private ArrayList<ViewData> viewDatas; private int w; private int h; private RectF rectF;
public MyView(Context context) { super(context); initPaint(); }
public void setData(ArrayList<ViewData> viewDatas) { this.viewDatas = viewDatas; initData(); invalidate(); }
public MyView(Context context, AttributeSet attrs) { super(context, attrs); initPaint(); }
public MyView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initPaint(); }
private void initPaint() { paint = new Paint(); paint.setColor(Color.WHITE); paint.setStyle(Paint.Style.FILL); paint.setTextSize(30); rectF = new RectF(); }
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); this.w = w; this.h = h; }
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.translate(w / 2, h / 2); float currentStartAngle = 0; float r = (float) (Math.min(w, h) / 2); rectF.set(-r, -r, r, r); for (int i = 0; i < viewDatas.size(); i++) { ViewData viewData = viewDatas.get(i); paint.setColor(viewData.color); canvas.drawArc(rectF, currentStartAngle, viewData.angle, true, paint); float textAngle = currentStartAngle + viewData.angle / 2; paint.setColor(Color.BLACK); float x = (float) (r / 2 * Math.cos(textAngle * Math.PI / 180)); float y = (float) (r / 2 * Math.sin(textAngle * Math.PI / 180)); paint.setColor(Color.YELLOW); canvas.drawText(viewData.name, x, y, paint);
currentStartAngle += viewData.angle; } }
private void initData() { if (null == viewDatas || viewDatas.size() == 0) { return; }
float sumValue = 0; for (int i = 0; i < viewDatas.size(); i++) { ViewData viewData = viewDatas.get(i); sumValue += viewData.value; int j = i % mColors.length; viewData.color = mColors[j]; }
for (ViewData data : viewDatas) { float percentage = data.value / sumValue; float angle = percentage * 360; data.percentage = percentage; data.angle = angle; } } }
|
最终实现效果就是开头那张了,自定义View还有很长路要走
完整代码请移步这里