框架地址:https://github.com/PhilJay/MPAndroidChart
因爲需求中大部分圖表的樣式都差不多,只有裏面的數據做了變化,而使用圖表的時候又需要對圖表進行各種各樣的配置,所以對圖表框架進一步封裝是有必要的。
我這裏將圖表的配置寫在一個類中,將常用的方法(數據,圖表顏色,描述,等等)令寫方法出來設置。。因爲使用的是建造者模式,可以根據需求定義。這裏封裝了線性圖、餅狀圖、柱狀圖、雷達圖。
寫了一個數據類ChartValue用來存放所需數據的XY值,然後將數據設置也封裝到了,配置類中,圖表構建完成後獲得圖表的View對象,填充到想要的佈局中去。
具體實現
ChartView數據類:用來存放X,Y軸值。
package cn.xiaolongonly.mpchartsample.bean;
/**
* @author xiaolong
* @version v1.0
* @function <描述功能>
* @date 2016/9/22-17:32
*/
public class ChartValue<T> {
public String xVal;
public T yVal;
public ChartValue() {
}
public ChartValue(String xVal, T yVal) {
this.xVal = xVal;
this.yVal = yVal;
}
}
Item項:每個需要的圖表構建一個item對象,存放固定配置和數據設置
package cn.xiaolongonly.mpchartsample.chart.item;
import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.AxisBase;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.ChartData;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.formatter.IAxisValueFormatter;
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
import java.util.ArrayList;
import java.util.List;
import cn.xiaolongonly.mpchartsample.R;
import cn.xiaolongonly.mpchartsample.bean.ChartValue;
import cn.xiaolongonly.mpchartsample.chart.markview.DataMarkView;
import cn.xiaolongonly.mpchartsample.chart.util.ColorTemplate;
public class LineChartItem extends BaseChartItem {
private String xDesc;
private String yDesc;
private DataMarkView dataMarkView;
public LineChartItem(ChartData cd, Context c, IAxisValueFormatter iAxisValueFormatter) {
super(cd, c, iAxisValueFormatter);
}
public LineChartItem(ChartData cd, Context c, DataMarkView dataMarkView, IAxisValueFormatter iAxisValueFormatter) {
super(cd, c, iAxisValueFormatter);
this.dataMarkView = dataMarkView;
}
@Override
public int getItemType() {
return TYPE_LINECHART;
}
public View getView() {
return getView(null);
}
public String getxDesc() {
return xDesc;
}
public void setxDesc(String xDesc) {
this.xDesc = xDesc;
}
public String getyDesc() {
return yDesc;
}
public void setyDesc(String yDesc) {
this.yDesc = yDesc;
}
@Override
public View getView(View convertView) {
ViewHolder holder = null;
if (convertView == null) {
holder = new ViewHolder();
convertView = LayoutInflater.from(mContext).inflate(
R.layout.list_item_linechart, null);
holder.chart = (LineChart) convertView.findViewById(R.id.chart);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
// apply styling
LineChart lineChart = (LineChart) holder.chart;
lineChart.setBackgroundColor(mContext.getResources().getColor(R.color.chart_bg));
lineChart.getLegend().setPosition(Legend.LegendPosition.ABOVE_CHART_LEFT);
lineChart.getLegend().setForm(Legend.LegendForm.CIRCLE);
// 設置無數據文本提示
lineChart.setDescription(null);
// lineChart.setNoDataText(mContext.getResources().getString(R.string.chart_no_data));
// lineChart.setXYDesc(xDesc, yDesc);
if (!xDesc.equals("") || !yDesc.equals("")) {
lineChart.setXYDesc(xDesc, yDesc, 10f, mContext.getResources().getColor(R.color.normal_black_color));
}
//設置單方向和雙方向縮放 true x,y方向可以同時控制,false只能控制x方向的縮小放大或者Y方向的縮小放大
lineChart.setPinchZoom(true);
DataMarkView dataMarkView = new DataMarkView(mContext, 0, "");
lineChart.setMarkerView(dataMarkView);
lineChart.setDrawGridBackground(false);
XAxis xAxis = lineChart.getXAxis();
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM); //定製X軸是在圖表上方還是下方。
xAxis.setDrawGridLines(false);
xAxis.setGranularity(1);//放大的時候X值不增多
xAxis.setValueFormatter(mIAxisValueFormatter);
if (dataMarkView != null) {
lineChart.setMarkerView(dataMarkView);
}
YAxis yAxisRight = lineChart.getAxisRight();
yAxisRight.setEnabled(false);
YAxis yAxisLeft = lineChart.getAxisLeft();
yAxisLeft.setAxisMinimum(0);
// set data
lineChart.setData((LineData) mChartData);
// do not forget to refresh the chart
// holder.chart.invalidate();
lineChart.animateX(750);
lineChart.animateY(750);
return convertView;
}
public static class Builder {
private int[] colors = ColorTemplate.PIE_COLORS;
private String[] describles = new String[]{""};
private String xDesc = "";
private String yDesc = "";
private List<List<ChartValue>> charValueLists = new ArrayList<>();
private Context context;
private boolean isFillColor;
private ArrayList<String> labels = new ArrayList<>();
public Builder(Context context) {
this.context = context;
}
public Builder addChartValueList(List<ChartValue> charValueLists) {
this.charValueLists.add(charValueLists);
return this;
}
public Builder setChartValueList(List<List<ChartValue>> charValueLists) {
this.charValueLists = charValueLists;
return this;
}
public Builder setyDesc(String yDesc) {
this.yDesc = yDesc;
return this;
}
public Builder setxDesc(String xDesc) {
this.xDesc = xDesc;
return this;
}
public Builder setDescribles(String[] describles) {
this.describles = describles;
return this;
}
public Builder setColorReses(int[] colorReses) {
this.colors = new int[colorReses.length];
for (int i = 0; i < colors.length; i++) {
colors[i] = context.getResources().getColor(colorReses[i]);
}
return this;
}
public Builder fillColorEnable(boolean isFillColor) {
this.isFillColor = isFillColor;
return this;
}
public LineChartItem build() {
return build(null);
}
public LineChartItem build(DataMarkView dataMarkView) {
List<ILineDataSet> lineDataSets = new ArrayList<>();
for (int listIndexOutside = 0; listIndexOutside < charValueLists.size(); listIndexOutside++) {
ArrayList<Entry> entries = new ArrayList<Entry>();
for (int listIndexInside = 0; listIndexInside < charValueLists.get(listIndexOutside).size(); listIndexInside++) {
entries.add(new Entry((float) listIndexInside, (float) charValueLists.get(listIndexOutside).get(listIndexInside).yVal));
if (listIndexOutside == 0) {
labels.add(charValueLists.get(listIndexOutside).get(listIndexInside).xVal);
}
}
lineDataSets.add(generateLineDataSet(entries, describles[listIndexOutside], colors[listIndexOutside % colors.length]));
}
IAxisValueFormatter iAxisValueFormatter = new IAxisValueFormatter() {
@Override
public String getFormattedValue(float value, AxisBase axis) {
return labels.get((int) value % labels.size());
}
};
LineData cd = new LineData(lineDataSets);
LineChartItem lineChartItem = null;
if (dataMarkView != null) {
lineChartItem = new LineChartItem(cd, context, dataMarkView, iAxisValueFormatter);
} else {
lineChartItem = new LineChartItem(cd, context, iAxisValueFormatter);
}
lineChartItem.setxDesc(xDesc);
lineChartItem.setyDesc(yDesc);
return lineChartItem;
}
private ILineDataSet generateLineDataSet(ArrayList<Entry> entries, String describle, int color) {
LineDataSet dataSet = new LineDataSet(entries, describle);
dataSet.setLineWidth(2.0f);
dataSet.setCircleRadius(3.5f);
dataSet.setDrawCircleHole(true);//填充圓
dataSet.setValueTextSize(9f);
dataSet.setHighlightLineWidth(2.0f);
dataSet.setDrawFilled(isFillColor);
dataSet.setFillAlpha(51);
dataSet.setFillColor(color); //填充色
dataSet.setHighLightColor(color); //選中十字線色
dataSet.setColor(color); //線條顏色
dataSet.setCircleColor(color); //圓點顏色
dataSet.setCircleColorHole(Color.WHITE);
dataSet.setCircleHoleRadius(2.0f);
dataSet.setDrawValues(false);
return dataSet;
}
}
}
當然如果需求圖表有其他樣式的的話,我覺得也可以把配置信息抽取出來,通過不同的配置來設置不同的樣式。
在Activity中的使用
package cn.xiaolongonly.mpchartsample.ui;
import android.widget.RelativeLayout;
import java.util.ArrayList;
import java.util.List;
import cn.xiaolongonly.mpchartsample.R;
import cn.xiaolongonly.mpchartsample.base.BaseTitleActivity;
import cn.xiaolongonly.mpchartsample.bean.ChartValue;
import cn.xiaolongonly.mpchartsample.chart.item.LineChartItem;
/**
* @author xiaolong
* @version v1.0
* @function <描述功能>
* @date 2016/12/5-17:32
*/
public class LineChartActivity2 extends BaseTitleActivity {
private RelativeLayout rlContent;
@Override
protected int getLayoutId() {
return R.layout.activity_chart;
}
@Override
protected void initView() {
rlContent = findView(R.id.rlContent);
List<ChartValue> chartValues = new ArrayList<>();
chartValues.add(new ChartValue("11月", 110f));
chartValues.add(new ChartValue("10月", 120f));
chartValues.add(new ChartValue("9月", 100f));
List<ChartValue> chartValues2 = new ArrayList<>();
chartValues2.add(new ChartValue("11月", 155f));
chartValues2.add(new ChartValue("10月", 133f));
chartValues2.add(new ChartValue("9月", 122f));
LineChartItem lineChartItem = new LineChartItem.Builder(this).setxDesc("單位(月)")
.setyDesc("單位(萬)").setDescribles(new String[]{"項目支出金額"})
.addChartValueList(chartValues).addChartValueList(chartValues2)
.build();
rlContent.addView(lineChartItem.getView());
}
@Override
protected void setListener() {
}
}
是不是就簡單多了只要構建一個Item對象,然後將item對象的圖表佈局,add到View中去就可以了。
實現效果
總結
一直都沒想到有一天我也能這麼寫代碼,感覺代碼寫多了很多東西就懂了。
在最開始的時候老大讓我對圖表框架進行二次封裝,我聽的一臉懵逼,經過一段時間的思考,反覆對照之前的項目,因爲之前的項目的配置都寫在繼承的圖表中,在xml佈局中要將圖表改成繼承的圖表,數據導入也寫在了Activity類中,感覺代碼特別多且雜,後來想到了一句話,多用組合少用繼承,現在看來確實,組合的方式會比繼承好很多。雖然參考了好多代碼,封裝的也不怎麼樣,但是我確實是做到了。
那時候跟同時說我把圖表框架封裝完的時候,同事說,不會啊封裝的不錯。對於我這種渣渣來講就是莫大的安慰了。離自己的目標又近了一步。加油~~