首先看一下效果图,把2种数据,叠加展示。
下面我们来看一下代码是如何实现的。
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.效果如下。实现方式很简单。就是自己写个类似的布局。然后在自定义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条了。这样多余数据可以滑动查看。 当数据少的时候,柱状图也不会被放大。固定了宽度了。