今天讲图表统计中比较常用的一个,像支付宝的月账单啥的,都是用圆饼图来做数据统计的,先看一下我最终实现的效果图:
image.png
该效果实际上是两个实心圆叠加后的效果。
image.png
image.png
《一》View实现思路分析:
(1)根据占比集合数据,计算所需绘制的角度,动态设置画笔颜色,drawArc()绘制外圆弧
(2)drawCircle()绘制内圆
(3)确定每块圆饼的小白点的位置
(4)绘制白点的沿线和占比文字
《二》具体实现:
(1)绘制不同颜色的圆饼
for (int i = 0; i < mRateList.size(); i++) {
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(mColorList.get(i));
// Log.e("TAG", "startAngle=" + startAngle + "--sweepAngle=" + ((int) (mRateList.get(i) * (360)) - offset));
canvas.drawArc(rectF, startAngle, (int) (mRateList.get(i) * (360)) , true, mPaint);
startAngle = startAngle + (int) (mRateList.get(i) * 360);
}
(2)绘制内圆
mPaint.setColor(ContextCompat.getColor(mContext, R.color.color_081638));
canvas.drawCircle(radius + centerPointRadius + (xOffset + yOffset + textRect.width()), radius + centerPointRadius + (xOffset + yOffset + textRect.height()), radius / 1.5f, mPaint);
(3)确定每块圆饼的小白点的位置,通过每段圆饼的起始角度确定该段圆弧的中心点位置。
private void dealPoint(RectF rectF, float startAngle, float endAngle, List pointList) {
Path path = new Path();
//通过Path类画一个90度(180—270)的内切圆弧路径
path.addArc(rectF, startAngle, endAngle);
PathMeasure measure = new PathMeasure(path, false);
// Log.e("路径的测量长度:", "" + measure.getLength());
float[] coords = new float[]{0f, 0f};
//利用PathMeasure分别测量出各个点的坐标值coords
int divisor = 1;
measure.getPosTan(measure.getLength() / divisor, coords, null);
// Log.e("coords:", "x轴:" + coords[0] + " -- y轴:" + coords[1]);
float x = coords[0];
float y = coords[1];
Point point = new Point(Math.round(x), Math.round(y));
pointList.add(point);
}
(4)绘制以白点为起点的折线和占比文字。有个细节需要注意一下,绘制折线和比例文字时,每部分沿线和文字的绘制规则不一样,我是按下面的规则处理的:将圆分为四部分,每块区分显示。
image.png
//折线横向长度
private int xOffset;
//折线偏Y方向长度
private int yOffset;
private void dealRateText(Canvas canvas, Point point, int position, List pointList) {
if (position == 0) {
lastPoint = pointList.get(0);
} else {
lastPoint = pointList.get(position - 1);
}
float[] floats = new float[8];
floats[0] = point.x;
floats[1] = point.y;
//右半圆
if (point.x >= radius + centerPointRadius + (xOffset + yOffset + textRect.width())) {
mPaint.setTextAlign(Paint.Align.LEFT);
floats[6] = point.x + xOffset;
if (point.y <= radius &#