首先看一下效果图,把2种数据,叠加展示。

snap javacore分析 snap chart application_ci

下面我们来看一下代码是如何实现的。

1.首先我把实现堆叠柱状图封装了MyBarChart。下面直接上代码。

代码里面直接把设置chart的一些属性配置好了。对外暴露了一个设置数据的接口。使用的时候在直接调用

setBarDataSet() 方法,传相应的参数设置数据。
public class MyBarChart extends BarChart{
    private ValueFormatter mXAxisFormatter;
    protected Typeface tfLight;
    private Context context;
    public MyBarChart(Context context) {
        super(context);
        tfLight = Typeface.createFromAsset(context.getAssets(), "OpenSans-Light.ttf");
        this.context=context;
        initSetting();
    }

    public MyBarChart(Context context, AttributeSet attrs) {
        super(context, attrs);
        tfLight = Typeface.createFromAsset(context.getAssets(), "OpenSans-Light.ttf");
        this.context=context;
        initSetting();
    }

    public MyBarChart(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        tfLight = Typeface.createFromAsset(context.getAssets(), "OpenSans-Light.ttf");
        this.context=context;
        initSetting();
    }

    /**
     *
     */
    public  void initSetting() {
        setDrawBarShadow(false);//设置阴影
        setDrawValueAboveBar(true);//设置所有的数值在图形的上面,而不是图形上
        getDescription().setEnabled(false);//不描述
        // if more than 60 entries are displayed in the chart, no values will be
        // drawn     // 如果60多个条目显示在图表,drawn没有值
        setMaxVisibleValueCount(60);

        // scaling can now only be done on x- and y-axis separately
        setPinchZoom(false);//设置true支持两个指头向X、Y轴的缩放,如果为false,只能支持X或者Y轴的当方向缩放
        setDrawGridBackground(false);//设置背景是否网格显示
        // chart.setDrawYLabels(false);
        // TODO 把这个设置为false,禁用所有手势和图表上的触摸,默认:true
//        setTouchEnabled(false);
        //设置是否可以缩放。false不能放大缩小。但是如果显示不全可以左右滑动
        setScaleEnabled(false);
        // TODO 设置图标拖动为允许
//        chart.setDragEnabled(false);

        //TODO 这个控制横坐标的显示内容
//        mXAxisFormatter = new StringDataAxisValueFormatter();

        XAxis xAxis = getXAxis();
        xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
        xAxis.setTypeface(tfLight);
        xAxis.setDrawGridLines(false);
//        xAxis.setTextSize(9);
        xAxis.setGranularity(1f); // only intervals of 1 day
//        xAxis.setValueFormatter(mXAxisFormatter);
        xAxis.setLabelRotationAngle(-60);//设置x坐标的文字倾斜。为倾斜60°
//        xAxis.setAxisMinimum(0f);


        ValueFormatter custom = new MyValueFormatter("$");//这里是y轴的显示内容

        YAxis leftAxis = getAxisLeft();
        leftAxis.setTypeface(tfLight);
        leftAxis.setLabelCount(8, true);//这里设置y轴坐标数的个数。包含0点,后面设为true,才可固定左边y轴有几个坐标值
//        leftAxis.setValueFormatter(custom);
        leftAxis.setPosition(YAxis.YAxisLabelPosition.OUTSIDE_CHART);
        leftAxis.setSpaceTop(15f);
        leftAxis.setAxisMinimum(0f); //保证y轴从0开始 不然会上移一点 this replaces setStartAtZero(true)
//        leftAxis.setDrawGridLines(false);//去掉中间横线
//有坐标轴显示内容
        YAxis rightAxis = getAxisRight();
        rightAxis.setEnabled(false);

        /** 图例的属性 */
        Legend l = getLegend();
        l.setEnabled(false);  //不显示图例 底部的什么颜色代表什么的说明
        //决定底部图例的位置。
        l.setVerticalAlignment(Legend.LegendVerticalAlignment.TOP);
        l.setHorizontalAlignment(Legend.LegendHorizontalAlignment.CENTER);
        l.setOrientation(Legend.LegendOrientation.HORIZONTAL);
        l.setDrawInside(false);
        l.setForm(Legend.LegendForm.SQUARE);
        l.setFormSize(9f);
        l.setTextSize(11f);
        l.setXEntrySpace(10f);

//        XYMarkerView mv = new XYMarkerView(context, mXAxisFormatter);
//        mv.setChartView(this); // For bounds control
//        setMarker(mv); // Set the marker to the chart

//        setExtraBottomOffset(20);
    }

    public void setBarDataSet(List<BarEntry> values, String label, String[] StackLabels ) {
        BarDataSet set1;
//TODO  这里去掉此种方法赋值是因为遇到如果第一次无数据,第二次再有数据的情况会导致柱状图颜色不叠加。不是2个颜色。官方demo也是这样。
//        if (getData() != null &&
//                getData().getDataSetCount() > 0) {
//            set1 = (BarDataSet) getData().getDataSetByIndex(0);
//            set1.setValues(values);
//            getData().notifyDataChanged();
//            notifyDataSetChanged();
//
//        } else {
            set1 = new BarDataSet(values, label);
            set1.setDrawIcons(true);
//TODO 这里是设置颜色的。
            int startColor1 = ContextCompat.getColor(context, R.color.yiban_color);
            int startColor2 = ContextCompat.getColor(context, R.color.xiaoguimo_color);
            List<Integer> colors = new ArrayList<>();
            colors.add(startColor1);
            colors.add(startColor2);
            set1.setColors(colors);
//            set1.setStackLabels(new String[]{"一般人","小规模"});
            set1.setStackLabels(StackLabels);
            ArrayList<IBarDataSet> dataSets = new ArrayList<>();
            dataSets.add(set1);

            BarData data = new BarData(dataSets);
            data.setValueTextSize(10f);
            data.setValueTypeface(tfLight);
            data.setBarWidth(0.4f);//这个是个百分百比,1表示占满100%, 0.5表示50%  代表柱状图的宽度。值越大柱状图越宽
            data.setDrawValues(false); // 设置是否显示数据点的值
            //设置数据
            setData(data);
//        }
        invalidate();
        //TODO 设置完数据后。必须设置完数据后才有效设置最大显示11个。多的话需要滑动查看, 这样固定住了 12个少的话。也不会放大
        setVisibleXRangeMaximum(12);
        setVisibleXRangeMinimum(12);

    }
}

2.在布局文件里,引入我们刚才自定义的MyBarChart

<com.lyf.demo.view.MPChart.MyBarChart
            android:id="@+id/barChart"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_below="@id/rl_title"
            android:layout_marginBottom="10dp" />

3.在Acitivity里面。我们拿到MyBarChart对象。然后给MyBarChart设置数据。

(1)看一下我们的网络数据是一个list,里面的BarDateBean内容

public class BarDataBean  implements Serializable {
  
   private String ssdsmc;//城市,或者区县  x轴内容
   private float ybr;//  订单个数  y轴内容
   private float xgm;//  订单个数  y轴内容
   private float hj;//合计

    public BarDataBean(String ssdsmc, float ybr, float xgm, float hj) {
        this.ssdsmc = ssdsmc;
        this.ybr = ybr;
        this.xgm = xgm;
        this.hj = hj;
    }

   //set,get方法我这里就不粘贴了。
}

(2)得到网络数据后我们如何给柱状图设置数据代码如下。

private String[] mSsLable = new String[]{"手机", "电脑"};//图例

ArrayList<BarEntry> values = new ArrayList<>();//柱状图需要的数据,values是网络得到的数据。得到数据后调用setChartData方法设置数据就可以。(values的数据可以自己模拟几条感受一下)

/**
     * 设置柱状图和折线图的数据。x轴和y轴的数据
     */
    private void setChartData() {
        getBarChartData();//把网络数据转为柱状图需要的数据类型
        setXAxis(barChart.getXAxis());//设置x轴的数据
        barChart.setBarDataSet(values, "", mSsLable);//设置y轴的数据,和图例
        
    }


 /**
     * 把得到的网络是数据转为BarChart需要的数据类型。
     */
    private void getBarChartData() {
        values.clear();
        //下面是设置Y轴的数据,自己得到的数据类型转为chart需要的数据类型
        for (int i = 0; i < valueList.size(); i++) {
            values.add(new BarEntry(i, new float[]{valueList.get(i).getYbr(), valueList.get(i).getXgm()}));//两个是float类型的
        }
    }


  private void setXAxis(XAxis xAxis) {
        /**  (1)第一种就是先给x轴设置ValueFOrmatter,然后这里直接刷新。(2)或者就是不设置。这里直接设置。
         第一种更新一下,x轴的数据。这样到x轴得到了更新,点击某个弹出的悬浮框内容也得到了更新。或者悬浮框也在这里设置market*/
//        ((StringDataAxisValueFormatter)mXAxisFormatter).refreshList(valueList);

        StringDataAxisValueFormatter xFormatter = new StringDataAxisValueFormatter() {  //设置每个x轴的内容
            @Override
            public String getFormattedValue(float value) {//这个value是那边BarEntry得到的x的值。
                try {
                   String cityName= (valueList.get((int) value)).getSsdsmc();
                   if(cityName.length()>4){//这里是如果x轴文字长,就3个字后面用省略号
                           String bb = cityName.substring(0, 3);
                           cityName=bb+"...";
                   }
                    return cityName;
                } catch (Exception e) {
                    e.printStackTrace();
                    return "";
                }

            }
        };
        xAxis.setValueFormatter(xFormatter);
        int barLayoutId=R.layout.my_custom_marker_view;
      
        MyCustomMarkerView barMv = new MyCustomMarkerView(this, valueList,barLayoutId);
        
//        mv.setChartView(barChart); // For bounds control

        barChart.setMarker(barMv); // 柱状图设置market
      
        xAxis.setLabelCount(valueList.size());//TODO 这里决定者x轴显示的个数  拿到数据库再设置显示个数,也不确定起作用了没,反正后面加上true。就都乱了
    }
4.在上图setXAxis方法中。用到了自己写的MarkerView。就是点击柱状图弹出的marketView.效果如下。

snap javacore分析 snap chart application_数据_02

实现方式很简单。就是自己写个类似的布局。然后在自定义MarkerView。下面上代码MyCustomMarkerView

public class MyCustomMarkerView extends MarkerView {

    private final TextView tvContent;
    private final TextView tv_yiban;
    private final TextView tv_xiaoguimo;
    List<BarDataBean> valueList;

    public MyCustomMarkerView(Context context, List<BarDataBean> valueList,int layoutId) {
//        super(context, R.layout.my_custom_marker_view);
        super(context, layoutId);
        tvContent = findViewById(R.id.tvContent);
        tv_yiban = findViewById(R.id.tv_yiban);
        tv_xiaoguimo = findViewById(R.id.tv_xiaoguimo);
        this.valueList=valueList;
    }

    // runs every time the MarkerView is redrawn, can be used to update the
    // content (user-interface)
    @Override
    public void refreshContent(Entry e, Highlight highlight) {
        try {
//            tvContent.setText(String.format("x: %s, y: %s", xAxisValueFormatter.getFormattedValue(e.getX()), format.format(e.getY())));
            float index = e.getX();//因为没有用formatter转。所有这里e.getX得到的索引号
            int pos = (int) index;
            tvContent.setText(valueList.get(pos).getSsdsmc());
//            Log.e("marker",e.getData().toString());e.mYVals[0]
            tv_yiban.setText((int)(valueList.get(pos).getYbr())+"");
            tv_xiaoguimo.setText((int)(valueList.get(pos).getXgm())+"");

        }catch (Exception ex){
           ex.printStackTrace();
        }
        super.refreshContent(e, highlight);
    }

    @Override
    public MPPointF getOffset() {
        return new MPPointF(-(getWidth() / 2), -getHeight());
    }
}

总结一下:

1.由于我的需求是根据时间段查询数据。显示柱状图。所以选择时间后。柱状图数据不停的在改变包括x轴,遇到问题,当从无数据到有数据的时候。x轴内容文字会遮盖,解决办法是:拿到数据之后,从无到有数据状态,调用两遍setChartData()就可了。

2.从无到有数据适合。会出现柱状图不叠加了。而是颜色间隔显示。已经在封装的MyBarChart解决了。

3.设置完数据之后。setVisibleXRangeMaximum(12);        setVisibleXRangeMinimum(12); 设置可见最大最小都是12条,意思就是固定12条了。这样多余数据可以滑动查看。 当数据少的时候,柱状图也不会被放大。固定了宽度了。