美文网首页
MPAndroidChart(4)——柱状图BarChart的使

MPAndroidChart(4)——柱状图BarChart的使

作者: 古早味蛋糕 | 来源:发表于2022-11-01 10:20 被阅读0次

    本文相关代码

    MPAndroidChart在github上地址:https://github.com/PhilJay/MPAndroidChart

    目标效果图为某公司的净资产收益率:

    7.png
    1. 数据准备

    1.1 数据来源

    数据是抓包佣金宝的数据,将获取的数据存入.json文件。
    https://gitee.com/zyd_gitee/android-mp-charts/blob/master/app/src/main/assets/line_chart.json

    1.png
    2. 图表显示

    2.1 MPAndroidChart获取

    Github 地址:https://github.com/PhilJay/MPAndroidChart

    依赖:
    Project 的build.gradle文件中添加


    2.png

    然后在Project 的settings.gradle 中添加


    3.png
    然后在 module中的build,gradle 中添加
    implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
    

    2.2 数据对象获取
    在Android Studio app项目src同级目录下新建中新建assets文件夹,然后将步骤1.1得到的.json文件放入改文件夹中。

    然后在获取.json文件中的json字符串并解析为对应的数据对象,可参考以下文章

    相关文章:Android访问assets本地Json文件[[(18条消息) Android访问assets本地Json文件

    在此就不详叙述了,只是列出图表展示所需要的类

        /**
         * 公司净资产收益率
         */
        public static class VtDateValueBean {
            /**
             * fValue : -21.7467
             * sYearMonth : 2018-03
             */
    
            private double fValue;
            private String sYearMonth;
        }
    
        /**
         * 行业平均值
         */
        public static class VtDateValueAvgBean {
            /**
             * fValue : 7.50136
             * sYearMonth : 2016-12
             */
    
            private double fValue;
            private String sYearMonth;
        }
    

    2.3.1 BarChart 的使用流程

    使用流程如下

    得到BarChart对象 并初始化
    得到BarEntry对象,此处添加(X,Y)值
    得到BarDataSet对象,添加BarEntry对象
    得到BarData对象,添加BarDaraSet对象
    显示柱状图 BarChart.setData(BarData)

    BarChart与折线图LineChart很类似,基本会使用到如下属性

    private BarChart barChart;
    private YAxis leftAxis;             //左侧Y轴
    private YAxis rightAxis;            //右侧Y轴
    private XAxis xAxis;                //X轴
    private Legend legend;              //图例
    private LimitLine limitLine;        //限制线
    

    然后进行相应的设置

        /**
     * 初始化BarChart图表
     */
    private void initBarChart(BarChart barChart) {
        /***图表设置***/
        //背景颜色
        barChart.setBackgroundColor(Color.WHITE);
        //不显示图表网格
        barChart.setDrawGridBackground(false);
        //背景阴影
        barChart.setDrawBarShadow(false);
        barChart.setHighlightFullBarEnabled(false);
        //显示边框
        barChart.setDrawBorders(true);
        //设置动画效果
        barChart.animateY(1000, Easing.Linear);
        barChart.animateX(1000, Easing.Linear);
    
        /***XY轴的设置***/
        //X轴设置显示位置在底部
        xAxis = barChart.getXAxis();
        xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
        xAxis.setAxisMinimum(0f);
        xAxis.setGranularity(1f);
    
        leftAxis = barChart.getAxisLeft();
        rightAxis = barChart.getAxisRight();
        //保证Y轴从0开始,不然会上移一点
        leftAxis.setAxisMinimum(0f);
        rightAxis.setAxisMinimum(0f);
    
        /***折线图例 标签 设置***/
        legend = barChart.getLegend();
        legend.setForm(Legend.LegendForm.LINE);
        legend.setTextSize(11f);
        //显示位置
        legend.setVerticalAlignment(Legend.LegendVerticalAlignment.BOTTOM);
        legend.setHorizontalAlignment(Legend.LegendHorizontalAlignment.LEFT);
        legend.setOrientation(Legend.LegendOrientation.HORIZONTAL);
        //是否绘制在图表里面
        legend.setDrawInside(false);
    }
    

    2.3.2 BarDataSet 初始化设置

    BarDataSet与LineDataSet类似,一个BarDataSet对象就是一类柱状图,多列柱状图就是多个BarDataSet对象

        /**
     * 柱状图始化设置 一个BarDataSet 代表一列柱状图
     *
     * @param barDataSet 柱状图
     * @param color      柱状图颜色
     */
    private void initBarDataSet(BarDataSet barDataSet, int color) {
        barDataSet.setColor(color);
        barDataSet.setFormLineWidth(1f);
        barDataSet.setFormSize(15.f);
        //显示柱状图顶部值
        barDataSet.setDrawValues(true);
       //barDataSet.setValueTextSize(10f);
      //barDataSet.setValueTextColor(color);
    }
    

    2.3.3 柱状图展示

    此处先展示 公司的净资产收益率

        public void showBarChart(List<VtDateValueBean> dateValueList, String name, int color) {
        ArrayList<BarEntry> entries = new ArrayList<>();
        for (int i = 0; i < dateValueList.size(); i++) {
            /**
             * 此处还可传入Drawable对象 BarEntry(float x, float y, Drawable icon)
             * 即可设置柱状图顶部的 icon展示
             */
            BarEntry barEntry = new BarEntry(i, (float) dateValueList.get(i).getFValue());
            entries.add(barEntry);
        }
        // 每一个BarDataSet代表一类柱状图
        BarDataSet barDataSet = new BarDataSet(entries, name);
        initBarDataSet(barDataSet, color);
    
        BarData data = new BarData(barDataSet);
        barChart.setData(data);
    }
    

    然后在Activity中调用

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bar_chart);
    
        barChart = findViewById(R.id.bar_chart);
        initBarChart(barChart);
        BarChartBean barChartBean = LocalJsonAnalyzeUtil.JsonToObject(this,
                "bar_chart.json", BarChartBean.class);
        List<VtDateValueBean> dateValueList = barChartBean.getStFinDate().getVtDateValue();
        Collections.reverse(dateValueList);//将集合 逆序排列,转换成需要的顺序
    
        showBarChart(dateValueList, "净资产收益率(%)", getResources().getColor(R.color.blue));
    }
    

    注意:不了解数据怎么来的可查看 相关文章:Android访问assets本地Json文件 或者本文相关代码

    此时的图形效果

    3. 柱状图外观完善

    上图与需要实现的效果差距还是挺大的,下面待改善的点,然后挨着就行修改

    去掉图表外框,以及右下角描述内容
    去掉X Y轴实线,以及左侧Y轴
    X轴改为日期显示
    Y轴网格线改为虚线
    Y轴值改为百分比,且间隔值为10%
    靠近Y轴的柱状图未展示完整
    负数值的柱状图未展示完整

    3.1 去掉图表外框,描述内容以及X Y轴线条

    不显示图表边框

    barChart.setDrawBorders(false);
    

    不显示右下角描述内容

    Description description = new Description();
    description.setEnabled(false);
    barChart.setDescription(description);
    

    不显示X轴 Y轴线条

    xAxis.setDrawAxisLine(false);
    leftAxis.setDrawAxisLine(false);
    rightAxis.setDrawAxisLine(false);
    

    不显示左侧Y轴

     leftAxis.setEnabled(false);
    
    3.2 修改X Y轴网格线

    虽然我们设置了不显示与图表网格线

    barChart.setDrawGridBackground(false);
    

    但是因为X Y轴还有自己的网格线,所以看起来图表的网格线仍然存在,所以还需对X轴Y轴的网格线进行设置

     //不显示X轴网格线
     xAxis.setDrawGridLines(false);
     //右侧Y轴网格线设置为虚线
     rightAxis.enableGridDashedLine(10f, 10f, 0f);
    
    3.3 X Y轴自定义显示值

    在 showBarChart 方法中我们会传入X轴的值,所以自定义X轴的值可以 写在该方法内

       //X轴自定义值
        xAxis.setValueFormatter(new ValueFormatter() {
            @Override
            public String getAxisLabel(float value, AxisBase axis) {
                return dateValueList.get((int) value % dateValueList.size()).getTradeDate();
            }
        });
        //右侧Y轴自定义值
        rightAxis.setValueFormatter(new ValueFormatter() {
            @Override
            public String getAxisLabel(float value, AxisBase axis) {
                return (int) value + "%";
            }
        });
    
    3.4 柱状图显示负值

    在这里柱状图未显示完整,完全是我自己的问题,如果在 initBarChart(BarChart barChart) 方法中不设置X轴Y轴,柱状图默认情况下是能显示完整的。

    只需要在前面的基础上 删除 以下代码即可完整展示。

     xAxis.setAxisMinimum(0f);
     //保证Y轴从0开始,不然会上移一点
     leftAxis.setAxisMinimum(0f);
     rightAxis.setAxisMinimum(0f);
    

    但前面为什么会写上那三行代码呢,因为在LineCahrt中,想要保证X Y 轴完全以 0 点开始。而柱状图的因为柱子宽度的原因,X轴的0值不需要 完全靠近 原点(0,0)
    之后如图:


    4.png
    3.5 单条柱状图宽度

    BarData类有设置柱状图宽度的方法,查看源码可以发现,传入的值 mBarWidth不是 px 以像素为单位,而是一个百分百值,默认值为0.85f 相当就是85%

    宽度计算方式就是 BarChart控件宽度 / 柱状图数量 * mBarWidth ,以下为 设置值为 1 与 0.5 的效果

       BarData data = new BarData(barDataSet);
       data.setBarWidth(1f);
        barChart.setData(data);
    
    1f.png
        BarData data = new BarData(barDataSet);
        data.setBarWidth(0.5f);
        barChart.setData(data);
    
    0.5f.png
    4. 多条柱状图
    4.1 多条柱状图展示

    多条柱状图,多添加一个BarDataSet对象即可。

    /**
     * @param xValues   X轴的值
     * @param dataLists LinkedHashMap<String, List<Float>>
     *                  key对应柱状图名字  List<Float> 对应每类柱状图的Y值
     * @param colors
     */
    public void showBarChart(final List<String> xValues, LinkedHashMap<String, List<Float>> dataLists,
                             @ColorRes List<Integer> colors) {
    
        List<IBarDataSet> dataSets = new ArrayList<>();
        int currentPosition = 0;//用于柱状图颜色集合的index
    
        for (LinkedHashMap.Entry<String, List<Float>> entry : dataLists.entrySet()) {
            String name = entry.getKey();
            List<Float> yValueList = entry.getValue();
    
            List<BarEntry> entries = new ArrayList<>();
    
            for (int i = 0; i < yValueList.size(); i++) {
                entries.add(new BarEntry(i, yValueList.get(i)));
            }
            // 每一个BarDataSet代表一类柱状图
            BarDataSet barDataSet = new BarDataSet(entries, name);
            initBarDataSet(barDataSet, colors.get(currentPosition));
            dataSets.add(barDataSet);
    
            currentPosition++;
        }
    
        //X轴自定义值
        xAxis.setValueFormatter(new ValueFormatter() {
            @Override
            public String getAxisLabel(float value, AxisBase axis) {
                return xValues.get((int) value % xValues.size());
            }
        });
        //右侧Y轴自定义值
        rightAxis.setValueFormatter(new ValueFormatter() {
            @Override
            public String getAxisLabel(float value, AxisBase axis) {
                return (int) value + "%";
            }
        });
    
        BarData data = new BarData(dataSets);
        barChart.setData(data);
    }
    

    在Activity中调用

        //处理数据是 记得判断每条柱状图对应的数据集合 长度是否一致
        LinkedHashMap<String, List<Float>> chartDataMap = new LinkedHashMap<>();
        List<String> xValues = new ArrayList<>();
        List<Float> yValue1 = new ArrayList<>();
        List<Float> yValue2 = new ArrayList<>();
        List<Integer> colors = Arrays.asList(
                getResources().getColor(R.color.blue), getResources().getColor(R.color.orange)
        );
    
        List<CompanyBean> companyBeans = lineChartBean.getGRID0().getResult().getCompany();
        List<CompositeIndexBean> compositeIndexBeans = lineChartBean.getGRID0().getResult().getCompositeIndexGEM();
    
        for (CompanyBean valueBean : companyBeans) {
            xValues.add(valueBean.getTradeDate());
            yValue1.add(Float.valueOf(valueBean.getRate()));
        }
        for (CompositeIndexBean compositeIndexBean : compositeIndexBeans) {
            yValue2.add(Float.valueOf(compositeIndexBean.getRate()*100));
        }
        chartDataMap.put("净资产收益率(%)", yValue1);
        chartDataMap.put("行业平均值(%)", yValue2);
    
        barChartManager.showBarChart(xValues, chartDataMap, colors);
    
    5.png

    4.2 由堆积柱状图变为并排多列柱状图
    默认情况下,添加多条柱状图得到的效果是堆积柱状图,而现在需要的是 分组并列多条柱状图,所以还需要进行相应的设置。

    柱状图分组设置

        BarData data = new BarData(dataSets);
       /**
        * 并排多列柱状图
        * float groupSpace = 0.3f;   //柱状图组之间的间距
        * float barSpace =  0.05f;  //每条柱状图之间的间距  一组两个柱状图
        * float barWidth = 0.3f;    //每条柱状图的宽度     一组两个柱状图
        * (barWidth + barSpace) * barAmount + groupSpace = (0.3 + 0.05) * 2 + 0.3 = 1.00
        * 3个数值 加起来 必须等于 1 即100% 按照百分比来计算 组间距 柱状图间距 柱状图宽度
        */
       int barAmount = dataLists.size(); //需要显示柱状图的类别 数量
       //设置组间距占比30% 每条柱状图宽度占比 70% /barAmount  柱状图间距占比 0%
        float groupSpace = 0.3f; //柱状图组之间的间距
        float barWidth = (1f - groupSpace) / barAmount;
        float barSpace = 0f;
        //设置柱状图宽度
        data.setBarWidth(barWidth);
        //(起始点、柱状图组间距、柱状图之间间距)
        data.groupBars(0f, groupSpace, barSpace);
        barChart.setData(data);
    }
    

    以上代码注意这个算式:

    (barWidth + barSpace) * barAmount + groupSpace = (0.3 + 0.05) * 2 + 0.3 = 1.00
    

    柱状图宽度 间距 值设多少看需求来定,但最终必须根据以上公式算出来 等于 1

    现在的效果图


    6.png

    右侧还有部分图表未展示出来,此时还需要对X轴进行相应的设置

         //不加上会x轴显示不全 
        xAxis.setAxisMaximum(xValues.size());
        //将X轴的值显示在中央
        xAxis.setCenterAxisLabels(true);
    

    加上 xAxis.setCenterAxisLabels(true); 这行代码后,前面自定义X轴的显示值则数组越界异常。

    看错误日志是 X轴值为 -1,所以将自定义X轴的显示值改为:

       //X轴自定义值
        xAxis.setValueFormatter(new ValueFormatter() {
            @Override
            public String getAxisLabel(float value, AxisBase axis) {
                //加上 xAxis.setCenterAxisLabels(true); 这行代码后,前面自定义X轴的显示值则数组越界异常。
                //看错误日志是 X轴值为 -1,所以将自定义X轴的显示值改为:
                return xValues.get((int) Math.abs(value) % xValues.size());
            }
        });
    

    现在如图如示


    7.png
    5. BarChart触摸事件
    5.1 柱状图点击事件响应

    在平常使用中,用的最多的事件就是柱状图点击事件了。

       //点击事件
        barChart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() {
            @Override
            public void onValueSelected(Entry e, Highlight h) {
                e.getX();       //X轴坐标 记得转 int
                e.getY();       //当前柱状图Y轴值
                e.getIcon();    //对应 BarEntry(float x, float y, Drawable icon)
                e.getData();    //对应 BarEntry(float x, float y, Object data)
                Toast.makeText(BarChartActivity.this, "y:"+e.getY(), Toast.LENGTH_SHORT).show();
            }
    
            @Override
            public void onNothingSelected() {
            }
        });
    

    回调函数中的Entry对应showBarChart方法中 添加的BarEntry,可以在添加的时候 传入一个自定义数据,如name

    entries.add(new BarEntry(i, yValueList.get(i), name));
    然后在柱状图选中事件回调函数中得到我们自定义的数据 进行相应的识别。

       @Override
       public void onValueSelected(Entry e, Highlight h) {
            e.getData();    //对应 BarEntry(float x, float y, Object data)
       }
    

    通过e.getData()方法就可以得到我们前面设置的值,在此处为点击的柱状图名字,即哪一类柱状图,此方法很灵活。

    如果单纯的想知道点击的是哪一类柱状图可以采用以下方法:

      @Override
      public void onValueSelected(Entry e, Highlight h) {
           /得到包含此柱状图的 数据集
           BarDataSet dataSets = (BarDataSet) barChart.getBarData().getDataSetForEntry(e);
           dataSets.getLabel();
           dataSets.getEntryCount();
           List<BarEntry> barEntries = dataSets.getValues();
       }
    

    通过e.getX()方法可以得到点柱状图所对应的X轴数据,然后就可以知道X轴所对应的所以柱状图值

            @Override
            public void onValueSelected(Entry e, Highlight h) {
                for (IBarDataSet dataSet : barChart.getBarData().getDataSets()) {
                    BarEntry entry = dataSet.getEntryForIndex((int) e.getX());
                }
            }
    

    5.2 禁用图表触摸事件

    barChart.setDoubleTapToZoomEnabled(false);
    //禁止拖拽
    barChart.setDragEnabled(false);
    //X轴或Y轴禁止缩放
    barChart.setScaleXEnabled(false);
    barChart.setScaleYEnabled(false);
    barChart.setScaleEnabled(false);
    //禁止所有事件
    barChart.setTouchEnabled(false);
    

    本文相关代码:https://gitee.com/zyd_gitee/android-mp-charts.git

    相关文章

      网友评论

          本文标题:MPAndroidChart(4)——柱状图BarChart的使

          本文链接:https://www.haomeiwen.com/subject/uajhtdtx.html