Android 自定义饼状图
github 地址:https://github.com/dkest/PieView
简单分析
其实根据我们上面的知识已经能自己制作一个饼状图了。不过制作东西最重要的不是制作结果,而是制作思路。 相信我贴上代码大家一看就立刻明白了,非常简单的东西。不过嘛,咱们还是想了解一下制作思路:
先分析饼状图的构成,非常明显,饼状图就是一个又一个的扇形构成的,每个扇形都有不同的颜色,对应的有名字,数据和百分比。
经以上信息可以得出饼状图的最基本数据应包括:名字 数据值 百分比 对应的角度 颜色。
用户关心的数据 : 名字 数据值 百分比
需要程序计算的数据: 百分比 对应的角度
其中颜色这一项可以用户指
1 public class PieData { 2 3 private String name; // 名字 4 private float value; // 数值 5 private float percentage; // 百分比 6 7 private int color = 0; // 颜色 8 private float angle = 0; // 角度 9 10 public PieData(@NonNull String name, @NonNull float value) { 11 this.name = name; 12 this.value = value; 13 } 14 }
自定义View:
先按照自定义View流程梳理一遍(确定各个步骤应该做的事情):
步骤 | 关键字 | 作用 |
---|---|---|
1 | 构造函数 | 初始化(初始化画笔Paint) |
2 | onMeasure | 测量View的大小(暂时不用关心) |
3 | onSizeChanged | 确定View大小(记录当前View的宽高) |
4 | onLayout | 确定子View布局(无子View,不关心) |
5 | onDraw | 实际绘制内容(绘制饼状图) |
6 | 提供接口 | 提供接口(提供设置数据的接口) |
代码如下:
1 public class PieView extends View { 2 // 颜色表 3 private int[] mColors = {0xFFCCFF00, 0xFF6495ED, 0xFFE32636, 0xFF800000, 0xFF808000, 0xFFFF8C69, 0xFF808080, 4 0xFFE6B800, 0xFF7CFC00}; 5 // 饼状图初始绘制角度 6 private float mStartAngle = 0; 7 // 数据 8 private ArrayList<PieData> mData; 9 // 宽高 10 private int mWidth, mHeight; 11 // 画笔 12 private Paint mPaint = new Paint(); 13 14 public PieView(Context context) { 15 this(context, null); 16 } 17 18 public PieView(Context context, AttributeSet attrs) { 19 super(context, attrs); 20 mPaint.setStyle(Paint.Style.FILL); 21 mPaint.setAntiAlias(true); 22 } 23 24 @Override 25 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 26 super.onSizeChanged(w, h, oldw, oldh); 27 mWidth = w; 28 mHeight = h; 29 } 30 31 @Override 32 protected void onDraw(Canvas canvas) { 33 super.onDraw(canvas); 34 if (null == mData) 35 return; 36 float currentStartAngle = mStartAngle; // 当前起始角度 37 canvas.translate(mWidth / 2, mHeight / 2); // 将画布坐标原点移动到中心位置 38 float r = (float) (Math.min(mWidth, mHeight) / 2 * 0.8); // 饼状图半径 39 RectF rect = new RectF(-r, -r, r, r); // 饼状图绘制区域 40 41 for (int i = 0; i < mData.size(); i++) { 42 PieData pie = mData.get(i); 43 mPaint.setColor(pie.getColor()); 44 canvas.drawArc(rect, currentStartAngle, pie.getAngle(), true, mPaint); 45 currentStartAngle += pie.getAngle(); 46 } 47 48 } 49 50 // 设置起始角度 51 public void setStartAngle(int mStartAngle) { 52 this.mStartAngle = mStartAngle; 53 invalidate(); // 刷新 54 } 55 56 // 设置数据 57 public void setData(ArrayList<PieData> mData) { 58 this.mData = mData; 59 initDate(mData); 60 invalidate(); // 刷新 61 } 62 63 // 初始化数据 64 private void initDate(ArrayList<PieData> mData) { 65 if (null == mData || mData.size() == 0) // 数据有问题 直接返回 66 return; 67 68 float sumValue = 0; 69 for (int i = 0; i < mData.size(); i++) { 70 PieData pie = mData.get(i); 71 72 sumValue += pie.getValue(); //计算数值和 73 74 int j = i % mColors.length; //设置颜色 75 pie.setColor(mColors[j]); 76 } 77 78 float sumAngle = 0; 79 for (int i = 0; i < mData.size(); i++) { 80 PieData pie = mData.get(i); 81 82 float percentage = pie.getValue() / sumValue; // 百分比 83 float angle = percentage * 360; // 对应的角度 84 85 pie.setPercentage(percentage); // 记录百分比 86 pie.setAngle(angle); // 记录角度大小 87 sumAngle += angle; 88 89 Log.i("angle", "" + pie.getAngle()); 90 } 91 }
PS: 在更改了数据需要重绘界面时要调用invalidate()这个函数重新绘制。
效果图