上一篇讲的是折线图的实现例子:传送门 所以这篇条形图就不去过多的讲自定义控件的步骤了。
先上图看效果:
其它属性与上一篇折线图的属性基本一致,这里增加了一个条形图宽度的属性
<!--条形图的宽度--> <attr name="BarWidth" format="dimension" />话不多说,直接上核心代码:
/** * 绘制xtab和 图 */ private void drawAbscissaAndChart(Canvas canvas) { if (mLineData == null) return; xYAxisPaint.setColor(textColor); xYAxisPaint.setTextSize(axisSize); //条形图组总数 int barSize = mLineData.getDataSet().size(); for (int i = 0; i < mLineData.getLables().size(); i++) { String xLable = mLineData.getLables().get(i); xYAxisPaint.setTextAlign(Paint.Align.CENTER); //横坐标文字 canvas.save(); canvas.drawText(xLable, dotX + (barSize * i + (float) barSize / 2) * BarWidth + i * xScaleWidth, dotY + marginXy + xTabHeight, xYAxisPaint); canvas.restore(); } Rect rect = new Rect();//Rect对象 //多组条形图 for (int i = 0; i < barSize; i++) { //设置每组条形图的颜色 LineDataSet dataSet = mLineData.getDataSet().get(i); chartPaint.setColor(dataSet.getLineColor()); //绘制每组条形图 for (int j = 0; j < dataSet.getyVals().size(); j++) { Entry entry = dataSet.getyVals().get(j); rect.top = (int) getBarHeight(entry.getVal()); rect.bottom = (int) dotY; rect.left = (int) (dotX + j * xScaleWidth + (barSize * j + i) * BarWidth); rect.right = (int) (rect.left + BarWidth); canvas.drawRect(rect, chartPaint); //绘制数值 if (isShowValue) { //绘制折线点上的值 xYAxisPaint.setTextSize(axisSize * 2 / 3); xYAxisPaint.setTextAlign(Paint.Align.CENTER); canvas.drawText((int) entry.getVal() + "", rect.right - BarWidth / 2, getBarHeight(entry.getVal()) - marginXy, xYAxisPaint); } } } }这里关键的是算好标签的X 坐标值:
dotX + (barSize * i + (float) barSize / 2) * BarWidth + i * xScaleWidth那么第一组数据(i=0)的X轴的标签X坐标就是: 假设两组数据 barSize(条形图组数) = 2; X = dotx(原点x) + (2*0 +(float)2/2 ) * BarWidth(条形图宽度) + 0 * xScaleWidth(每组条形图间距)
绘制条形图用的方法是 canvas.drawRect(rect, paint); 第一个参数是一个Rect,第二个参数是paint;Rect主要是固定矩形的范围。
//多组条形图 for (int i = 0; i < barSize; i++) { //设置每组条形图的颜色 LineDataSet dataSet = mLineData.getDataSet().get(i); chartPaint.setColor(dataSet.getLineColor()); //绘制每组条形图 for (int j = 0; j < dataSet.getyVals().size(); j++) { Entry entry = dataSet.getyVals().get(j); rect.top = (int) getBarHeight(entry.getVal()); rect.bottom = (int) dotY; rect.left = (int) (dotX + j * xScaleWidth + (barSize * j + i) * BarWidth); rect.right = (int) (rect.left + BarWidth); canvas.drawRect(rect, chartPaint); //绘制数值 if (isShowValue) { //绘制折线点上的值 xYAxisPaint.setTextSize(axisSize * 2 / 3); xYAxisPaint.setTextAlign(Paint.Align.CENTER); canvas.drawText((int) entry.getVal() + "", rect.right - BarWidth / 2, getBarHeight(entry.getVal()) - marginXy, xYAxisPaint); } } }绘制条形图,这里我们关键需要确定计算的是 rect.left这个值,其它都比较简单;
这里我写的绘制逻辑是一组一组数据绘制的,也就是说绘制第一组数据中的第一个数据,那么接下来绘制的是第一组数据中的第二个数据,这样的情况下就必须预留出第二组数据的第一个数据位置。 代码逻辑如下:
rect.left = (int) (dotX + j * xScaleWidth + (barSize * j + i) * BarWidth);假设有两组数据,barSize = 2;i = 0(第一组);j = 0(第一组第一个数据)
rect.left = (dotX + 0 * xScaleWidth(条形图间隔) + (2* 0 + 0) * BarWidth(条形图宽度));这里最好用笔画个图就好理解了。
画好了条形图,这个数值就好弄了,直接取rect.right的值减去条形图宽度的一半,画笔设置 Paint.Align.CENTER绘制就可以了。
canvas.drawText((int) entry.getVal() + "", rect.right - BarWidth / 2, getBarHeight(entry.getVal()) - marginXy, xYAxisPaint);源码传送门