自定义View-条形图

Posted 小向往

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自定义View-条形图相关的知识,希望对你有一定的参考价值。

概述

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

效果图

先上图看效果:

实现

功能

  1. 支持多组数据同时展示
  2. 每组数据条形图颜色可以自定义
  3. 每个数据值显示在条形图上面位置
  4. 每组的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

源码传送门

以上是关于自定义View-条形图的主要内容,如果未能解决你的问题,请参考以下文章

Python matplotlib可视化:在Matplotlib中为坐标轴刻度添加自定义符号(例如,货币符号¥$等)水平条形图(horizontal bar)

R语言ggplot2可视化排序的柱状图(Ordered Bar Chart)自定义柱状图条形的颜色为可视化图像添加标题和副标题题注信息自定义轴坐标文本的角度

R语言ggplot2可视化可视化排序的棒棒糖图类似于排序的条形图(Lollipop Chart)为可视化图像添加标题和副标题题注信息自定义轴坐标文本的角度

如何使用jQuery或jqPlot自定义PrimeFaces条形图属性

Compose自定义条形进度条

Compose自定义条形进度条