今天写一个饼图自定义View的文章。由于公司的项目需要用到饼图,UI给的设计图和自己找的一个饼图框架的标题位置不符,所以就自己画了一个。
1,使用预览
PieChart mChart mChart = (PieChart) findViewById(R.id.pieChar);
mChart = (PieChart) findViewById(R.id.pieChar);
String[] titles = new String[] {"钱包余额","金钱袋资产","金宝箱资产"};
mChart.setTitles(titles);
int[] colors = new int[]{0xfff5a002,0xfffb5a2f,0xff36bc99};
mChart.setColors(colors);
mChart.setValues(new double[]{999,999,999});
mChart.postInvalidate();
需要传入标题和值,每个饼的颜色也可以重新设置,不传颜色值就用默认的。画饼图的难点就在数学计算和逻辑思维能力。
2代码分析
/**
* 获得每个值所占的角度
* @return
*/
private float[] getAngles(){
if(mValues == null || mValues.length == 0) return null;
double sum = 0;
int len = mTitles.length;
float[] angles = new float[len];
int gapCount = 0;//饼图间隙条数
for(int i=0;i<len;i++){
sum += mValues[i];
if(mValues[i]>0)
gapCount++;
}
float angle = 0;
pieAngle = 360 - gapCount*ANGLE_DIS;
for(int i=0;i<len-1;i++){
angles[i] = (float)(pieAngle*mValues[i]/sum);
angle += angles[i];
}
if(mValues[len-1]>0)
angles[len - 1] = pieAngle - angle;
return angles;
}
根据传过来的值计算每个值所占的角度,饼图之间有1°的间隙,
if(mValues[i]>0) gapCount++;只有值大于0时才画饼,才增加一条间隙。
pieAngle = 360 - gapCount*ANGLE_DIS;这里计算所有饼所占整个圆的角度。
if(mValues[len-1]>0) angles[len - 1] = pieAngle - angle;最后一个饼的角度为饼的总角度减去前面所有饼的角度之和,这样做是为了让所有饼的角度加起来等于pieAngle这个角度,减少除法运算的小数误差效果。
/**
* 在饼图的每个饼上写上百分比,必须放在计算了每个值所占的角度angles之后
* @param canvas
*/
private void setPieContentText(Canvas canvas){
float pre = 0;
float[] centerAngle = new float[mAngles.length];
for(int i=0;i<mAngles.length;i++){
if(mAngles[i] == 0) continue;
centerAngle[i] = ANGLE_DIS+mAngles[i]/2 + pre;
pre += mAngles[i];
}
float cenR = pieR*1.0f/2*3/5;
float lastPir = 1.0f;//为了使所有的%比加起来等于1
mTextPaint.setColor(0xFFFFFFFF);
float cenX = 0;
float cenY = 0;
for(int i=0;i<centerAngle.length;i++){
if(centerAngle[i]==0 ) continue;
float xa = (float) (cenR * Math.cos(centerAngle[i] * (Math.PI / 180)));
float ya = (float) (cenR * Math.sin(centerAngle[i] * (Math.PI / 180)));
cenX = getWidth()*1.0f/2+xa;
cenY = TOP_PADDING + pieR*1.0f/2 + ya;
mTextPaint.setTextSize(mPieTextSize);
double curPer = numDecimals(mAngles[i]/pieAngle);
String perMsg = i==centerAngle.length-1?percentFormat(lastPir):p