首先看一下效果圖,把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條了。這樣多餘數據可以滑動查看。 當數據少的時候,柱狀圖也不會被放大。固定了寬度了。