自定义View-条形图

    xiaoxiao2021-03-25  121

    概述

    上一篇讲的是折线图的实现例子:传送门 所以这篇条形图就不去过多的讲自定义控件的步骤了。

    效果图

    先上图看效果:

    实现

    功能

    支持多组数据同时展示每组数据条形图颜色可以自定义每个数据值显示在条形图上面位置每组的X轴lable居中显示

    自定义属性

    其它属性与上一篇折线图的属性基本一致,这里增加了一个条形图宽度的属性

    <!--条形图的宽度--> <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轴标签根据组数据居中显示

    canvas.drawText(xLable, dotX + (barSize * i + (float) barSize / 2) * BarWidth + i * xScaleWidth, dotY + marginXy + xTabHeight, 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);

    onDraw

    @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); drawOrdinate(canvas); drawAbscissaAndChart(canvas); }

    使用

    Layout

    <com.totcy.tchartlibrary.charts.BarChartView android:id="@+id/barChartView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@android:color/white" app:ChartLineWidth="1dp" app:ChartPandding="5dp" app:TextSize="10sp" app:YscaleHeight="32dp" app:BarWidth="14dp" />

    activity

    private void initData() { //just for test //X轴标签 ArrayList<String> lables = new ArrayList<>(); lables.add("一月"); lables.add("二月"); lables.add("三月"); lables.add("四月"); lables.add("五月"); lables.add("六月"); //折线集合 ArrayList<LineDataSet> lineDataSets = new ArrayList<>(); //折线数据1 LineDataSet lineDataSet1 = new LineDataSet(); lineDataSet1.setDotColor(Color.RED); lineDataSet1.setLineColor(Color.parseColor("#0696f5")); //折线数据1 Y value ArrayList<Entry> entries1 = new ArrayList<>(); entries1.add(new Entry(120, 0)); entries1.add(new Entry(20, 1)); entries1.add(new Entry(80, 2)); entries1.add(new Entry(37, 3)); entries1.add(new Entry(94, 4)); entries1.add(new Entry(234, 5)); lineDataSet1.setyVals(entries1); lineDataSets.add(lineDataSet1); //折线数据2 LineDataSet lineDataSet2 = new LineDataSet(); lineDataSet2.setDotColor(Color.RED); lineDataSet2.setLineColor(Color.parseColor("#60b027")); //折线数据2 Y value ArrayList<Entry> entries2 = new ArrayList<>(); entries2.add(new Entry(50, 0)); entries2.add(new Entry(70, 1)); entries2.add(new Entry(150, 2)); entries2.add(new Entry(77, 3)); entries2.add(new Entry(467, 4)); entries2.add(new Entry(124, 5)); lineDataSet2.setyVals(entries2); lineDataSets.add(lineDataSet2); //折线数据3 LineDataSet lineDataSet3 = new LineDataSet(); lineDataSet3.setDotColor(Color.RED); lineDataSet3.setLineColor(Color.parseColor("#f82522")); //折线数据3 Y value ArrayList<Entry> entries3 = new ArrayList<>(); entries3.add(new Entry(420, 0)); entries3.add(new Entry(80, 1)); entries3.add(new Entry(120, 2)); entries3.add(new Entry(197, 3)); entries3.add(new Entry(307, 4)); entries3.add(new Entry(184, 5)); lineDataSet3.setyVals(entries3); lineDataSets.add(lineDataSet3); mLineData = new LineData(lables, lineDataSets); } public void onClick(View view) { barChartView.setLineData(mLineData); }

    Github

    源码传送门

    转载请注明原文地址: https://ju.6miu.com/read-11252.html

    最新回复(0)