MPAndroidChart项目实战(二)——双平滑曲线(双折线
Demo补充中(UpDating):https://github.com/JinBoy23520/MPAndroidChartDemoByJin
我的CSDN:http://blog.csdn.net/dt235201314/article/details/54135182
一丶先看效果图
Gif图大小限制,效果不是很清晰,高清效果是特别帅的
二丶先说一下功能点
1.双折线图(平滑曲线),展现对比效果
2.X轴单位,默认显示在1(月)
3.Y轴单位(%)或者其他,但文字写上去总是有点丑,就没放在Y轴
4.MarkView这里的不同点在于,点击一个点显示相同X轴对比的数据
5.新版MPAndroidChart支持两条折现X长度不一样,就是有一条为null就只显示另一条,当长度不一同样可以显示,老版本(jar包版本)就不行。
6.解决MPAndroidChart在ViewPage+fragment里的滑动冲突
三丶看代码
MPAndroidChart库的导入与基本属性:(参考刘某人MPAndroidChart专栏),写得很详细(自己想写的但又落在别人后面,又少了增粉蹭浏览量的好机会)
MPAndroidChart常见设置属性(一)——应用层
Android图表库MPAndroidChart(十四)——在ListView种使用相同的图表
1.项目复用率很高,先得有个BaseChartEntry.Java
public abstract class BaseChartEntity<T extends Entry> {
protected BarLineChartBase mChart;
protected List<T>[] mEntries;
protected String[] labels;
protected int []mChartColors;
protected float mTextSize;
protected int mValueColor;
protected BaseChartEntity(BarLineChartBase chart, List<T> []entries, String[] labels,
int []chartColor, int valueColor, float textSize) {
this.mChart = chart;
this.mEntries = entries;
this.labels = labels;
this.mValueColor = valueColor;
this.mChartColors = chartColor;
// this.mTextSize = textSize;
this.mTextSize = 11f;
initChart();
}
/**
* <p>初始化chart</p>
*/
protected void initChart() {
initProperties();
setChartData();
initLegend(Legend.LegendForm.LINE, mTextSize, mValueColor);
initXAxis(mValueColor, mTextSize);
initLeftAxis(mValueColor, mTextSize);
}
private void initLeftAxis(int color, float textSize) {
YAxis leftAxis = mChart.getAxisLeft();
leftAxis.setTextColor(color);
leftAxis.setTextSize(textSize);
float yMax = mChart.getData().getYMax() == 0 ? 100f : mChart.getData().getYMax();
leftAxis.setAxisMaximum(yMax + yMax * 0.007f);
// leftAxis.setAxisMinimum(0f);
leftAxis.setDrawGridLines(false);
leftAxis.setGranularityEnabled(false);
leftAxis.setDrawZeroLine(false);
leftAxis.setLabelCount(6);
leftAxis.setAxisLineWidth(1f);
leftAxis.setAxisLineColor(mValueColor);
mChart.getAxisRight().setEnabled(false);
}
private void initXAxis(int color, float textSize) {
XAxis xAxis = mChart.getXAxis();
xAxis.setTextSize(textSize);
xAxis.setAxisMinimum(0);
xAxis.setTextColor(color);
xAxis.setDrawGridLines(false);
xAxis.setDrawAxisLine(true);
xAxis.setDrawLabels(true);
xAxis.setAxisLineWidth(1f);
xAxis.setLabelCount(8);
xAxis.setDrawLimitLinesBehindData(true);
xAxis.setAxisLineColor(mValueColor);
xAxis.setCenterAxisLabels(false);
xAxis.setAxisMinimum(mChart.getData().getXMin());
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
}
/**
* <p>初始化属性信息</p>
*/
private void initProperties() {
mChart.setNoDataText("");
// no description text
mChart.getDescription().setEnabled(false);
// enable touch gestures
mChart.setTouchEnabled(true);
mChart.setDragDecelerationFrictionCoef(0.9f);
// enable scaling and dragging
mChart.setDragEnabled(true);
mChart.setScaleXEnabled(true);
mChart.setPinchZoom(false);
mChart.setVisibleXRangeMaximum(6);
mChart.setScaleYEnabled(false);
mChart.setDrawGridBackground(false);
mChart.setHighlightPerDragEnabled(false);
// if disabled, scaling can be done on x- and y-axis separately
mChart.setPinchZoom(false);
}
/**
* <p>初始化Legend展示信息</p>
* @param form 样式
* @param legendTextSize 文字大小
* @param legendColor 颜色值
*/
public void initLegend(Legend.LegendForm form, float legendTextSize, int legendColor) {
// get the legend (only possible after setting data)
Legend l = mChart.getLegend();
// modify the legend ...
l.setForm(form);
l.setTextSize(legendTextSize);
l.setTextColor(legendColor);
//l.setYOffset(11f);
updateLegendOrientation(Legend.LegendVerticalAlignment.BOTTOM, Legend.LegendHorizontalAlignment.RIGHT, Legend.LegendOrientation.HORIZONTAL);
}
/**
* <p>图例说明</p>
* @param vertical 垂直方向位置 默认底部
* @param horizontal 水平方向位置 默认右边
* @param orientation 显示方向 默认水平展示
*/
public void updateLegendOrientation (Legend.LegendVerticalAlignment vertical, Legend.LegendHorizontalAlignment horizontal, Legend.LegendOrientation orientation) {
Legend l = mChart.getLegend();
l.setVerticalAlignment(vertical);
l.setHorizontalAlignment(horizontal);
l.setOrientation(orientation);
l.setDrawInside(false);
}
/**
* 图表value显示开关
*/
public void toggleChartValue () {
List<BaseDataSet> sets = mChart.getData().getDataSets();
for (BaseDataSet iSet : sets) {
iSet.setDrawValues(!iSet.isDrawValuesEnabled());
}
mChart.invalidate();
}
public void setMarkView (MarkerView markView) {
markView.setChartView(mChart); // For bounds control
mChart.setMarker(markView); // Set the marker to the chart
mChart.invalidate();
}
/**
* x/ylabel显示样式
* @param xvalueFromatter x
* @param leftValueFromatter y
*/
public void setAxisFormatter(IAxisValueFormatter xvalueFromatter, IAxisValueFormatter leftValueFromatter) {
mChart.getXAxis().setValueFormatter(xvalueFromatter);
mChart.getAxisLeft().setValueFormatter(leftValueFromatter);
mChart.invalidate();
}
protected abstract void setChartData();
/**
* value显示格式设置
* @param valueFormatter IValueFormatter
*/
public void setDataValueFormatter(IValueFormatter valueFormatter) {
mChart.getData().setValueFormatter(valueFormatter);
}
}
这里设置了一些简单属性和方法类似setMarkView等,方便统一使用。需要修改时重写方法修改就行。
2.下面这个类就厉害了,基本是根据设计图样式添加的一些属性方法(对应图表一的基本属性),同样修要修改时重写方法就可以哒
public class LineChartEntity extends BaseChartEntity<Entry> {
public LineChartEntity (LineChart lineChart, List<Entry> []entries, String[] labels,
int []chartColor, int valueColor, float textSize) {
super(lineChart, entries, labels, chartColor, valueColor, textSize);
}
@Override
protected void initChart() {
super.initChart();
mChart.getAxisLeft().setDrawGridLines(true);
mChart.getAxisLeft().enableGridDashedLine(10f, 15f, 0f);
mChart.getAxisLeft().setGridLineWidth(0.5f);
mChart.getAxisLeft().setGridColor(Color.parseColor("#f5f5f5"));
mChart.getAxisLeft().setDrawZeroLine(false);
mChart.getAxisRight().setDrawZeroLine(false);
mChart.getAxisRight().setZeroLineWidth(0f);
mChart.getAxisLeft().setZeroLineWidth(0f);
mChart.getAxisLeft().setDrawAxisLine(false);
mChart.getXAxis().setDrawAxisLine(false);
// mChart.setScaleMinima(1.38f, 1f);
// mChart.getXAxis().setDrawGridLines(true);
// mChart.getXAxis().enableGridDashedLine(20f, 20f, 0f);
}
@Override
protected void setChartData() {
LineDataSet []lineDataSet = new LineDataSet[mEntries.length];
if (mChart.getData() != null && mChart.getData().getDataSetCount() == mEntries.length) {
for(int index = 0, len = mEntries.length; index < len; index ++) {
List<Entry> list = mEntries[index];
lineDataSet[index] = (LineDataSet) mChart.getData().getDataSetByIndex(index);
lineDataSet[index].setValues(list);
}
mChart.getData().notifyDataChanged();
mChart.notifyDataSetChanged();
} else {
for (int index = 0, len = mEntries.length; index < len; index ++) {
lineDataSet[index] = new LineDataSet(mEntries[index], labels[index]);
lineDataSet[index].setAxisDependency(YAxis.AxisDependency.LEFT);
lineDataSet[index].setColor(mChartColors[index]);
lineDataSet[index].setLineWidth(1.5f);
lineDataSet[index].setCircleRadius(3.5f);
lineDataSet[index].setCircleColor(mChartColors[index]);
lineDataSet[index].setFillAlpha(25);
// lineDataSet[index].enableDashedLine(10f, 15f, 0f);
// lineDataSet[index].enableDashedHighlightLine(10f, 15f, 0f);
lineDataSet[index].setDrawCircleHole(false);
lineDataSet[index].setValueTextColor(mChartColors[index]);
// lineDataSet[index].setFillColor(ColorTemplate.colorWithAlpha(Color.YELLOW, 200));
}
// create a data object with the datasets
LineData data = new LineData(lineDataSet);
data.setValueTextSize(mTextSize);
// set data
mChart.setData(data);
mChart.animateX(2000, Easing.EasingOption.EaseInOutQuad);
}
}
/**
* <p>填充曲线以下区域</p>
* @param drawable 填充drawable
* @param filledColor 填充颜色值
* @param fill true:填充
*/
public void toggleFilled(Drawable []drawable, int []filledColor, boolean fill) {
List<ILineDataSet> sets = ((LineChart)mChart).getData().getDataSets();
for (int index = 0, len = sets.size(); index < len; index ++ ) {
LineDataSet set = (LineDataSet) sets.get(index);
if (drawable != null) {
set.setFillDrawable(drawable[index]);
} else if (filledColor != null){
set.setFillColor(filledColor[index]);
}
set.setDrawFilled(fill);
}
mChart.invalidate();
}
/**
* <p>绘制曲线上点</p>
* @param draw true:绘制
*/
public void drawCircle ( boolean draw) {
List<ILineDataSet> sets = ((LineChart)mChart).getData().getDataSets();
for (ILineDataSet iSet : sets) {
LineDataSet set = (LineDataSet) iSet;
set.setDrawCircles(draw);
}
mChart.invalidate();
}
/**
* 设置图表颜色值
* @param mode LineDataSet.Mode
*/
public void setLineMode (LineDataSet.Mode mode) {
List<ILineDataSet> sets = ((LineChart)mChart).getData().getDataSets();
for (ILineDataSet iSet : sets) {
LineDataSet set = (LineDataSet) iSet;
set.setMode(mode);
}
mChart.invalidate();
}
public void setEnableDashedLine (boolean enable) {
List<ILineDataSet> sets = ((LineChart)mChart).getData().getDataSets();
for (ILineDataSet iSet : sets) {
LineDataSet set = (LineDataSet) iSet;
if (enable) {
set.disableDashedLine();
} else {
// set.setFormLineWidth(1f);
// set.setFormLineDashEffect(new DashPathEffect(new float[]{10f, 5f}, 0f));
// set.setFormSize(15.f);
set.enableDashedLine(10f, 5f, 0f);
set.enableDashedHighlightLine(10f, 5f, 0f);
}
}
mChart.invalidate();
}
/**设置x缩放的最小最大值*/
public void setMinMaxScaleX(float minScaleX, float maxScaleX) {
mChart.getViewPortHandler().setMinMaxScaleX(minScaleX, maxScaleX);
}
}
每个方法上都有所标注,功能方法填充背景啊,绘制动画啊,折现类型啊,缩放最大值最小值啊等
说一下这个最大值最小值,当图标控件宽设为martch,那么1就是屏幕宽度,1.5就是1.5个屏幕宽度
当都设为同一个值时是就是不允许缩放,大于1可滑动,都等于1就是不可缩放不可滑动
3.V层应用重要方法
public void updateLineData (LineChart mChart ) {
List<ILineDataSet> sets = mChart.getData().getDataSets();
for (ILineDataSet iSet : sets) {
LineDataSet set = (LineDataSet) iSet;
set.setFillAlpha(255);
set.setDrawCircleHole(true);
}
mChart.getAxisLeft().setDrawGridLines(true);
mChart.getAxisLeft().enableGridDashedLine(10f, 0f, 0f);
mChart.getAxisLeft().setGridLineWidth(0.5f);
mChart.getAxisLeft().setGridColor(Color.parseColor("#f5f5f5"));
mChart.getXAxis().setDrawGridLines(true);
mChart.getXAxis().enableGridDashedLine(10f, 0f, 0f);
mChart.getXAxis().setGridLineWidth(0.5f);
mChart.getXAxis().setGridColor(Color.parseColor("#f5f5f5"));
mChart.invalidate();
}
这个方法就是重写折线图样式,相对于GIF图二,这里将圆点改为空心,填充背景透明度改为255最大就是没有
然后就是绘制X和Y轴网格,enableGridLines属性本来是绘制虚线属性,当后面两位都为0时就成了实线
好现在上最重要的方法(传入双折线图数值,线色,背景填充,X轴,Y轴样式,MarkView展现)
private void updateLinehart(final List<FansMonthListEntity> fansMonthList, LineChart lineChart, int[] colors, Drawable[] drawables, final String unit, List<Entry> values1, List<Entry> values2, final String[] labels) {
List<Entry>[] entries = new ArrayList[2];
entries[0] = values1;
entries[1] = values2;
LineChartEntity lineChartEntity = new LineChartEntity(lineChart, entries, labels, colors, Color.parseColor("#999999"), 12f);
lineChartEntity.drawCircle(true);
lineChart.setScaleMinima(1.0f, 1.0f);
// toggleFilled(lineChartEntity, drawables, colors);
lineChartEntity.setLineMode(LineDataSet.Mode.LINEAR);
lineChartEntity.initLegend(Legend.LegendForm.CIRCLE, 12f, Color.parseColor("#999999"));
lineChartEntity.updateLegendOrientation(Legend.LegendVerticalAlignment.TOP, Legend.LegendHorizontalAlignment.RIGHT, Legend.LegendOrientation.HORIZONTAL);
lineChartEntity.setAxisFormatter(
new IAxisValueFormatter() {
@Override
public String getFormattedValue(float value, AxisBase axis) {
if (value == 1.0f) {
return mFormat.format(value) + mContext.getResources().getString(R.string.line_x_unit_month);
}
String monthStr = mFormat.format(value);
if (monthStr.contains(".")) {
return "";
} else {
return monthStr;
}
// return mMonthFormat.format(value);
}
},
new IAxisValueFormatter() {
@Override
public String getFormattedValue(float value, AxisBase axis) {
return mFormat.format(value) + unit;
}
});
lineChartEntity.setDataValueFormatter(new IValueFormatter() {
@Override
public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
return mFormat.format(value) + unit;
}
});
final NewMarkerView markerView = new NewMarkerView(mContext, R.layout.custom_marker_view_layout);
markerView.setCallBack(new NewMarkerView.CallBack() {
@Override
public void onCallBack(float x, String value) {
int index = (int) (x);
if (index < 0) {
return;
}
if (index > fansMonthList.size()) {
return;
}
String textTemp = "";
String monthUnit = mContext.getResources().getString(R.string.home_text_month);
if (index <= fansMonthList.size()) {
textTemp += labels[0] + "(" + index + monthUnit + ")" + ":" + mFormat.format(Float.parseFloat(fansMonthList.get(index - 1).getFansNum())) + unit;
textTemp += "\n";
textTemp += labels[1] + "(" + index + monthUnit + ")" + ":" + mFormat.format(Float.parseFloat(fansMonthList.get(index - 1).getFansRealNum())) + unit;
}
markerView.getTvContent().setText(textTemp);
}
});
lineChartEntity.setMarkView(markerView);
lineChart.getData().setDrawValues(false);
}
好,重要的代码都展现在这里。
不好意思贴掉了一个类NewMarkerView详情见博客:
MPAndroidChart项目实战——MarkerView显示问题解决
最后谈一谈开发时遇到的一些bug
1.lineChart滑动冲突
参考:MPAndroidChart在ViewPager+Fragment滑动冲突解决
2.当数据都为0时,X轴成一条直线,有时还出现负数,Y轴被压缩,文字重复显示,特别丑
mChart.getAxisLeft().setAxisMinimum(0);mChart.getAxisLeft().setAxisMaximum((float) (mChart.getData().getYMax() *1.1 + 20));
解决方法设置Y轴最小值为0,最大值为获得的最大值得1.1倍加20
这样既不会出现负数Y轴数值也不会压缩在一起
3.日月图表切换时,月表无辜变特别长,日X轴30~31个点,月12个点
解决方法:日月切换时重新设定缩放倍数
linechart.getViewPortHandler().setMinMaxScaleX(2,2);
4.markview,这个是真难,代码如上,但是大神帮忙解决的
总结:
MPAndroidChart是很好的开源库,新老版本改变差别较大,各有利弊。但jar包版(老版本)和新版本能共存,可解决很多问题
当开源库不能达到需求时,就要修改开源库,这个对于目前的我太难了,而同事能做到,这方便要加强,对开源源码的解读要加强
文章写到这里希望对大家能有帮助,不懂的地方直接评论问,另外,文章画了不少时间希望能成为我的第一篇技术文章,希望大家支持