框架地址: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> charValueLists = new ArrayList<>();
private Context context;
private boolean isFillColor;
private ArrayList labels = new ArrayList<>();
public Builder(Context context) {
this.context = context;
}
public Builder addChartValueList(List charValueLists) {
this.charValueLists.add(charValueLists);
return this;
}
public Builder setChartValueList(List> 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 lineDataSets = new ArrayList<>();
for (int listIndexOutside = 0; listIndexOutside < charValueLists.size(); listIndexOutside++) {
ArrayList entries = new ArrayList();
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 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 chartValues = new ArrayList<>();
chartValues.add(new ChartValue("11月", 110f));
chartValues.add(new ChartValue("10月", 120f));
chartValues.add(new ChartValue("9月", 100f));
List 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中去就可以了。
项目github下载
一直都没想到有一天我也能这么写代码,感觉代码写多了很多东西就懂了。
在最开始的时候老大让我对图表框架进行二次封装,我听的一脸懵逼,经过一段时间的思考,反复对照之前的项目,因为之前的项目的配置都写在继承的图表中,在xml布局中要将图表改成继承的图表,数据导入也写在了Activity类中,感觉代码特别多且杂,后来想到了一句话,多用组合少用继承,现在看来确实,组合的方式会比继承好很多。虽然参考了好多代码,封装的也不怎么样,但是我确实是做到了。
那时候跟同时说我把图表框架封装完的时候,同事说,不会啊封装的不错。对于我这种渣渣来讲就是莫大的安慰了。离自己的目标又近了一步。加油~~