本篇参考:​​GcsSloop的安卓自定义View进阶-Canvas之绘制图形​

自定义饼状图控件PieView_宽高

一、分析如上饼状图,所需要得信息如下

  1. 各块的颜色
  2. 所有块量得总和
  3. 各个块得量占总量的百分比,并通过百分比得到各个块所占扇形的弧度
  4. 第一个块得起始角度
  5. 该 View 控件的宽高及位置

二、具体控件逻辑

  1. javabean
public class PieData {
// 用户操作数据
private String name; // 名字
private float value; // 数值
private float percentage; // 百分比

// 非用户操作数据
private int color = 0; // 颜色
private float angle = 0; // 角度

public PieData(String name, float value) {
this.name = name;
this.value = value;
}

... // set/get省略
}
  1. 自定义PieView
public class PieView extends View {
// 1. 各块的颜色
private int[] mColors = {0xFFCCFF00, 0xFF6495ED, 0xFFE32636, 0xFF800000, 0xFF808000, 0xFFFF8C69, 0xFF808080, 0xFFE6B800, 0xFF7CFC00};
// 2. 第一块的初始角度
private float mStartAngle = 180;
// 数据集合
private ArrayList<PieData> mDatas;
// 控件宽高
private int mWidth, mHeight;
// 画笔
private Paint mPaint = new Paint();

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

public PieView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setAntiAlias(true);
}

// 记录当前View控件的宽高
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth = w;
mHeight = h;
}

// 设置起始角度并刷新界面
public void setStartAngle(int mStartAngle) {
this.mStartAngle = mStartAngle;
invalidate();
}

// 设置数据并刷新界面
public void setData(ArrayList<PieData> mData) {
this.mDatas = mData;
initData(mData);
invalidate();
}

// 饼状图中数据的处理
float sumValue = 0; // 所有块的数据总量
float piePercentage = 0; // 各块占数据总量的百分比
float sumAngle = 0; // 所有块占的总扇形角度
float pieAngle = 0; // 各块占的扇形角度
private void initData(ArrayList<PieData> mDatas) {
// 判空
if (null == mDatas || mDatas.size() == 0) {
return;
}

for (int i = 0; i < mDatas.size(); i++) {
PieData pie = mDatas.get(i);

// 1. 设置各块颜色
int j = i % mColors.length;
pie.setColor(mColors[j]);

// 2. 统计所有块的数据总量
sumValue += pie.getValue();

// 3. 计算各块量占总量的百分比
piePercentage = pie.getValue() / sumValue;

// 4. 通过各块量的占比计算所占扇形角度
pieAngle = piePercentage * 360;

pie.setPercentage(piePercentage);
pie.setAngle(pieAngle);
sumAngle += pieAngle;
}
}

@Override protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 判空
if (null == mDatas || mDatas.size() == 0) {
return;
}

// 记录当前起始角度
float currentStartAngle = mStartAngle;
// 将画布坐标原点移动到中心
canvas.translate(mWidth / 2, mHeight / 2);
// 饼状图半径
float r = (float) (Math.min(mWidth, mHeight) / 2 * 0.8);
// 确定饼状图绘制的区域
RectF rect = new RectF(-r, -r, r, r);

for (int i = 0; i < mDatas.size(); i++) {
PieData pie = mDatas.get(i);
mPaint.setColor(pie.getColor());
canvas.drawArc(rect, currentStartAngle, pie.getAngle(), true, mPaint);
currentStartAngle += pie.getAngle();
}
}
}
  1. 针对上述部分代码片的图解

自定义饼状图控件PieView_饼状图_02