首先看一下效果图,把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 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 colors = new ArrayList<>();
colors.add(startColor1);
colors.add(startColor2);
set1.setColors(colors);
// set1.setStackLabels(new String[]{"一般人","小规模"});
set1.setStackLabels(StackLabels);
ArrayList 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
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
/**
* 设置柱状图和折线图的数据。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 valueList;
public MyCustomMarkerView(Context context, List 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条了。这样多余数据可以滑动查看。 当数据少的时候,柱状图也不会被放大。固定了宽度了。