不比不知道,好程序员怎么写饼状图?

一张饼图

最近在学习HenCoder的自定义View的系列教程,刚看完第一章基础知识(虽然会,但是还是觉得跟着走一遍教程会比较好),之后开始做作业,作业都比较简单,无非就是一些基础的Api的调用,为了扎实基础而做的,但是我发现最后一张饼图,我虽然做出来了,但是很多知识都不确定,代码写的也不优美,比如从饼图上延伸出的线和文字的位置我就是用硬编码写出来的,非常的不友好,于是开始翻看别人的代码,几乎大同小异,都是写的硬编码,知道我看到了一个网友提交的作业后,眼前一亮,功力不可谓不高深啊!

饼图

直接贴人家的代码:

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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

public class Practice11PieChartView extends View {
private static final int RADIUS = 200;// 半径
private static final int LINE_LENGTH = 50;// 线的长度
private static final int OFFSET = 20;// 扇形偏移距离
private static final int OFFSET_INDEX = 2;// 偏移的扇形
private Paint arcPaint, linePaint, textPaint;
private RectF rectF;
private String[] names = {"a", "bb", "ccc", "dddd", "eeeee"};
private int[] percents = {10, 20, 30, 25, 15};
private int[] colors = {Color.WHITE, Color.YELLOW, Color.BLUE, Color.GRAY, Color.GREEN};

public Practice11PieChartView(Context context) {
this(context, null);
}

public Practice11PieChartView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}

public Practice11PieChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}

private void init() {
arcPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
arcPaint.setStyle(Paint.Style.FILL);

linePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
linePaint.setStrokeWidth(3);
linePaint.setColor(Color.WHITE);

textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint.setTextSize(30);
textPaint.setColor(Color.WHITE);

rectF = new RectF(-RADIUS, -RADIUS, RADIUS, RADIUS);
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

// 综合练习
// 练习内容:使用各种 Canvas.drawXXX() 方法画饼图

float startAngle = 0;

canvas.translate(getWidth() / 2, getHeight() / 2);// 画布移到中心

for (int i = 0; i < percents.length; i++) {
// 扇形的角度
float sweepAngle = 360 * percents[i] / 100;
// 扇形的中心线相对于坐标系的角度(0~2π)
double theta = (startAngle + sweepAngle / 2) * Math.PI / 180;

if (i == OFFSET_INDEX) {// 偏移的扇形
canvas.save();
// 计算该扇形的圆心偏移坐标,并移动画布到圆心
canvas.translate((float) (OFFSET * Math.cos(theta)), (float) (OFFSET * Math.sin(theta)));
drawContent(canvas, startAngle, sweepAngle, theta, i);
canvas.restore();
} else {
drawContent(canvas, startAngle, sweepAngle, theta, i);
}

startAngle += sweepAngle;
}

}

/**
* 画每个扇形的内容:扇形、线、文字
*
* @param canvas
* @param startAngle
* @param sweepAngle
* @param theta
* @param i
*/

private void drawContent(Canvas canvas, float startAngle, float sweepAngle, double theta, int i) {
Log.d("test", "i = " + i + ", theta = " + theta);

// 画扇形
arcPaint.setColor(colors[i]);
canvas.drawArc(rectF, startAngle, sweepAngle, true, arcPaint);

// 画斜线
float lineStartX = (float) (RADIUS * Math.cos(theta));
float lineStartY = (float) (RADIUS * Math.sin(theta));
float lineStopX = (float) ((RADIUS + LINE_LENGTH) * Math.cos(theta));
float lineStopY = (float) ((RADIUS + LINE_LENGTH) * Math.sin(theta));
canvas.drawLine(lineStartX, lineStartY, lineStopX, lineStopY, linePaint);

// 画横线和文字
float lineEndX;
Rect r = getTextBounds(names[i], textPaint);
if (theta > Math.PI / 2 && theta <= Math.PI * 3 / 2) {// 左半边,往左画横线
lineEndX = lineStopX - LINE_LENGTH;
// 画线
canvas.drawLine(lineStopX, lineStopY, lineEndX, lineStopY, linePaint);

// 画文字
canvas.drawText(names[i], lineEndX - r.width() - 10, lineStopY + r.height() / 2, textPaint);
} else {// 往右画横线
lineEndX = lineStopX + LINE_LENGTH;
// 画线
canvas.drawLine(lineStopX, lineStopY, lineEndX, lineStopY, linePaint);

// 文字
canvas.drawText(names[i], lineEndX + 10, lineStopY + r.height() / 2, textPaint);
}
}

/**
* 测量文字大小
*
* @param text
* @param paint
* @return
*/

private Rect getTextBounds(String text, Paint paint) {
Rect rect = new Rect();
paint.getTextBounds(text, 0, text.length(), rect);
return rect;
}
}

看完之后,自觉汗颜,很多算法和实现方式上确实有差距,学习了!

热评文章