因为一直喜欢琢磨界面,所以总爱翻跟界面有关的文章。之前在HenCoder上看到自定义View的教学,就跟着敲出了饼图和柱状图:
饼图
柱状图
一、饼图
1、数据初始化
饼图绘制的关键是角度,获取数据后将各个数据在总数中的占比转化成角度进行绘制。
/*数据总和*/
sum = 0;
/*饼图每部分开始绘制的角度*/
startAngle = 0;
/*饼图每部分结束绘制的角度*/
endAngle = 0;
/*获取数值总和,最大数值及其下标*/
for (int i=0;i<values.length;i++) {
sum+=values[i];
if(values[i]>=maxValue){
maxValue = values[i];
maxIndex = i;
Log.d(TAG,"maxValue:"+maxValue);
Log.d(TAG,"maxIndex:"+maxIndex);
}
}
Log.d(TAG,"sum:"+sum);
textPaint = new Paint();
paint = new Paint();
path = new Path();
paint.setAntiAlias(true);/*开启抗锯齿*/
2、绘制数值
获取画布的宽高,设置恰当的半径,开始绘制。
if(values.length>0&&values.length==datas.length){
init();
int width = getWidth();
int height = getHeight();
int r = Math.min(width,height)/2;
paint.setStyle(Paint.Style.STROKE);
paint.setColor(textColor);
paint.setStrokeWidth(strokeWidth);
textPaint.setTextSize(percentSize);
/*圆的半径*/
int R = (int)(r- r*0.15f);
/*绘制数值*/
for (int i=0; i<values.length; i++){
float percent = values[i]/sum;
startAngle = endAngle;
endAngle+=360 * percent;
angle = endAngle - startAngle;
Log.d(TAG,"startAngle:"+startAngle);
Log.d(TAG,"endAngle:"+endAngle);
Log.d(TAG,"angle:"+angle);
/*判断是否在绘制最大值的文字*/
xMaxOffset = maxIndex==i?offset*(float)Math.cos(Math.toRadians(startAngle+angle/2)):0;
yMaxOffset = maxIndex==i?offset*(float)Math.sin(Math.toRadians(startAngle+angle/2)):0;
float xOffset = (offset+DensityUtil.dip2px(getContext(),2))
*(float)Math.cos(Math.toRadians(startAngle+angle/2));
float yOffset = (offset+DensityUtil.dip2px(getContext(),2))
*(float)Math.sin(Math.toRadians(startAngle+angle/2));
Log.d(TAG,"xMaxOffset:"+xMaxOffset);
Log.d(TAG,"yMaxOffset:"+yMaxOffset);
x = R*(float)Math.cos(Math.toRadians(startAngle+angle/2));
y = R*(float)Math.sin(Math.toRadians(startAngle+angle/2));
path.moveTo(width/2+xOffset+xMaxOffset+x*0.3f,height/2+yOffset+yMaxOffset+y*0.3f);
path.rLineTo(x*0.7f,y*0.7f);
canvas.drawPath(path,paint);
if(startAngle+angle/2>90&&startAngle+angle/2<270){
path.rLineTo(-stripValue,0);
textPaint.setTextAlign(Paint.Align.RIGHT);
canvas.drawText(String.format("%.2f", percent*100)+"%",
width/2+x-text2strip+xOffset+xMaxOffset,height/2+y+yOffset+yMaxOffset,textPaint);
}else {
path.rLineTo(stripValue,0);
textPaint.setTextAlign(Paint.Align.LEFT);
canvas.drawText((String.format("%.2f", percent*100))+"%",
width/2+x+text2strip+xOffset+xMaxOffset,height/2+y+yOffset+yMaxOffset,textPaint);
}
canvas.drawPath(path,paint);
}
3、绘制饼图和文字
衔接上面的代码开始绘制饼图和文字
/*绘制饼图*/
startAngle=endAngle=angle=0;
paint.setStyle(Paint.Style.FILL);
RectF oval=new RectF(); //RectF对象
for (int i=0; i<values.length; i++){
float percent = values[i]/sum;
startAngle = endAngle;
endAngle+=360 * percent;
angle = endAngle - startAngle;
/*最大一部分的xy轴偏移量*/
xMaxOffset = maxIndex==i?offset*(float)Math.cos(Math.toRadians(startAngle+angle/2)):0;
yMaxOffset = maxIndex==i?offset*(float)Math.sin(Math.toRadians(startAngle+angle/2)):0;
/*饼图每一部分的偏移量,这样才能绘制出缝隙*/
float xOffset = offset*(float)Math.cos(Math.toRadians(startAngle+angle/2));
float yOffset = offset*(float)Math.sin(Math.toRadians(startAngle+angle/2));
oval.left=width/2-r+r*PIE_PERCENT+xOffset+xMaxOffset; //左边
oval.top=height/2-r+r*PIE_PERCENT+yOffset+yMaxOffset; //上边
oval.right=width/2+r-r*PIE_PERCENT+xMaxOffset; //右边
oval.bottom=height/2+r-r*PIE_PERCENT+yMaxOffset; //下边
/*防止最后一部分与第一部分的颜色重叠*/
if (i==values.length-1&&i%ChartColor.COLORNUMMBER==0){
paint.setColor(colors[i%ChartColor.COLORNUMMBER+1]);
}else {
paint.setColor(colors[i%ChartColor.COLORNUMMBER]);
}
canvas.drawArc(oval,startAngle,angle,true,paint);
x = (R)*(float)Math.cos(Math.toRadians(startAngle+angle/2));
y = (R)*(float)Math.sin(Math.toRadians(startAngle+angle/2));
textPaint.setTextAlign(Paint.Align.CENTER);
}
/*为防止饼图的最后一部分将第一个文字覆盖,将文字的绘制独立了出来*/
for (int i=0; i<values.length; i++){
float percent = values[i]/sum;
startAngle = endAngle;
endAngle+=360 * percent;
angle = endAngle - startAngle;
x = (R)*(float)Math.cos(Math.toRadians(startAngle+angle/2));
y = (R)*(float)Math.sin(Math.toRadians(startAngle+angle/2));
textPaint.setTextSize(textSize);
canvas.drawText(datas[i],width/2+x*2/3,height/2+y*2/3,textPaint);
}
}
二、柱状图
柱状图就是绘制矩形和xy轴,难点是沿着y轴绘制y轴坐标名称,解决的办法是沿折线绘制文字。
1、数据初始化
/*获取最大数值*/
for (float value : values) {
if(value >= max){
max = value;
}
}
/*画布宽高*/
width = getWidth();
height = getHeight();
/*每个柱子间的间隙*/
spacing = (width-2*marginLeft)*0.3f/(values.length+1);
/*柱子的宽度*/
bgWidth = (width-2*marginLeft)*0.7f/(values.length);
/*柱子的最高高度*/
maxHeight = height-5*marginBottom;
/*y轴距左边缘的偏移值*/
leftOffset = (unit!=""&&Yname!="") ? DensityUtil.dip2px(getContext(),10):0;
2、绘制xy轴与y轴坐标名称
/*绘制xy轴*/
path = new Path();
paint = new Paint();
textPaint = new Paint();
textPaint.setTextSize(textSize);
textPaint.setTextAlign(Paint.Align.CENTER);
paint.setStyle(Paint.Style.STROKE);
path.moveTo(marginLeft+leftOffset,marginBottom);
path.rLineTo(0,height-3*marginBottom);
canvas.drawPath(path,paint);
/*绘制y轴坐标名称*/
if(unit!=""&&Yname!=null){
canvas.drawTextOnPath(Yname+"/"+unit,path,-(height-10*marginBottom)/2,textSize*3/2,textPaint);
}
path.rLineTo(width-2*marginLeft,0);
canvas.drawPath(path,paint);
3、绘制柱子和数据
/*绘制柱子和文字*/
startXposition = marginLeft+spacing+leftOffset;
startYposition = marginBottom+height-3*marginBottom;
paint.setStyle(Paint.Style.FILL);
paint.setColor(ChartColor.VIOLETRED);
/*柱子的左上角与右下角*/
float left = 0;
float top = 0;
float right = 0;
float bottom = 0;
int i = 0;
for (float value : values) {
left = startXposition;
top = startYposition - value/max * maxHeight;
right = startXposition + bgWidth;
bottom = startYposition;
canvas.drawRect(left,top,right,bottom,paint);
canvas.drawText(String.valueOf(value),startXposition+bgWidth/2,top-marginBottom/2,textPaint);
canvas.drawText(datas[i],startXposition+bgWidth/2,startYposition+marginBottom*3/2,textPaint);
startXposition = startXposition + spacing + bgWidth;
i++;
}
三、使用
1、添加依赖
2.饼图
在xml里添加布局
<com.mils.mychart.chart.PieChartView
android:id="@+id/pc"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
添加数据与数据名称
float[] values = new float[]{5,2,7,25,40,20,30,10,10,4,10,4};
String[] datas = new String[]{"语文","数学","英语","文综","理综","数学","英语","文综","理综","理综","文综","理综"};
pcView.setValues(values);
pcView.setDatas(datas);
设置文字与数值字体大小,默认为10dp
pcView.setPercentSize(10f);
pcView.setTextSize(10f);
3、柱状图
在xml里添加布局
<com.mils.mychart.chart.BarGraphView
android:id="@+id/bg"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
添加数据与数据名称
float[] values = new float[]{5,2,7,25,40,20,30,10,10,4,10,4};
String[] datas = new String[]{"语文","数学","英语","文综","理综","数学","英语","文综","理综","理综","文综","理综"};
bgView.setValues(values);
bgView.setData(datas);
添加y轴坐标单位与名称
bgView.setYaxis("分","分数");
设置柱状图颜色
bgView.setChartColor(ChartColor.ORANGEYELLOW);
END
github地址:https://github.com/Mils-liu/MyChart
HenCoder教程地址:https://hencoder.com/activity-mock-2/
网友评论