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()這個函數重新繪制。
效果圖

