发现最新的MPAndroidChart和以前版本的使用有一些差距,就写下了现在新版的使用方法
注:2018-06-01更新,当前MPAndroidChart版本:3.0.3
本文涉及文章:
Android图表控件MPAndroidChart的简单介绍(MPAndroidChart3.0)
Android图表控件MPAndroidChart——LineChart实现 X、Y轴以及原点线的直尺刻度样式
其他相关文章:
Android图表控件MPAndroidChart——曲线图LineChart的使用(多条曲线)
Android图表控件MPAndroidChart——曲线图LineChart(多条曲线)动态添加数据
Android图表控件MPAndroidChart——柱状图BarChart的使用(多条柱状图)
Android图表控件MPAndroidChart——曲线图+柱状图 CombinedChart的使用
本文将要实现的图表效果,个人财富收益图,代码地址:
https://github.com/897532167/ChartManager.git
1.数据准备
1.1 数据来源
数据是抓包佣金宝的数据,将获取的数据存入.json文件。
json格式如下
Json 文件地址:
https://github.com/897532167/ChartManager/blob/master/app/src/main/assets/line_chart.json
2.曲线展示
2.1 MPAndroidChart获取
Github 地址:https://github.com/PhilJay/MPAndroidChart
依赖:
Project 的build.gradle文件中添加
allprojects {
repositories {
maven { url 'https://jitpack.io' }
}
}
然后在 module中的build,gradle 中添加
implementation 'com.github.PhilJay:MPAndroidChart:v3.0.3'
然而大多情况下,我们会根据自己的需求自定义MPAndroidChart库,则需要下载源码并将MPChartLib引入自己的项目中。
2.2 数据对象获取
在Android Studio app项目src同级目录下新建中新建assets文件夹,然后将步骤1.1得到的.json文件放入改文件夹中。
然后在获取.json文件中的json字符串并解析为对应的数据对象,可参考以下文章
在此就不详叙述了,只是列出图表展示所需要的类
/** * 我的收益 */ public class IncomeBean { /** * tradeDate : 20180502 * value : 0.03676598 */ private String tradeDate; private double value; } /** * 沪深创指数 */ public class CompositeIndexBean { /** * rate : -0.00034196 * tradeDate : 20180502 */ private String rate; private String tradeDate; }
2.3 数据展示
2.3.1 LineChart 图表初始化设置
LineChart曲线图表一会使用到如下属性
private LineChart lineChart; private XAxis xAxis; //X轴 private YAxis leftYAxis; //左侧Y轴 private YAxis rightYaxis; //右侧Y轴 private Legend legend; //图例 private LimitLine limitLine; //限制线 // private MyMarkerView markerView; //标记视图 即点击xy轴交点时弹出展示信息的View 需自定义
然后进行相应的设置
/** * 初始化图表 */ private void initChart(LineChart lineChart) { /***图表设置***/ //是否展示网格线 lineChart.setDrawGridBackground(false); //是否显示边界 lineChart.setDrawBorders(true); //是否可以拖动 lineChart.setDragEnabled(false); //是否有触摸事件 lineChart.setTouchEnabled(true); //设置XY轴动画效果 lineChart.animateY(2500); lineChart.animateX(1500); /***XY轴的设置***/ xAxis = lineChart.getXAxis(); leftYAxis = lineChart.getAxisLeft(); rightYaxis = lineChart.getAxisRight(); //X轴设置显示位置在底部 xAxis.setPosition(XAxis.XAxisPosition.BOTTOM); xAxis.setAxisMinimum(0f); xAxis.setGranularity(1f); //保证Y轴从0开始,不然会上移一点 leftYAxis.setAxisMinimum(0f); rightYaxis.setAxisMinimum(0f); /***折线图例 标签 设置***/ legend = lineChart.getLegend(); //设置显示类型,LINE CIRCLE SQUARE EMPTY 等等 多种方式,查看LegendForm 即可 legend.setForm(Legend.LegendForm.LINE); legend.setTextSize(12f); //显示位置 左下方 legend.setVerticalAlignment(Legend.LegendVerticalAlignment.BOTTOM); legend.setHorizontalAlignment(Legend.LegendHorizontalAlignment.LEFT); legend.setOrientation(Legend.LegendOrientation.HORIZONTAL); //是否绘制在图表里面 legend.setDrawInside(false); }
2.3.2 LineDataSet 曲线初始化设置
/** * 曲线初始化设置 一个LineDataSet 代表一条曲线 * * @param lineDataSet 线条 * @param color 线条颜色 * @param mode */ private void initLineDataSet(LineDataSet lineDataSet, int color, LineDataSet.Mode mode) { lineDataSet.setColor(color); lineDataSet.setCircleColor(color); lineDataSet.setLineWidth(1f); lineDataSet.setCircleRadius(3f); //设置曲线值的圆点是实心还是空心 lineDataSet.setDrawCircleHole(false); lineDataSet.setValueTextSize(10f); //设置折线图填充 lineDataSet.setDrawFilled(true); lineDataSet.setFormLineWidth(1f); lineDataSet.setFormSize(15.f); if (mode == null) { //设置曲线展示为圆滑曲线(如果不设置则默认折线) lineDataSet.setMode(LineDataSet.Mode.CUBIC_BEZIER); } else { lineDataSet.setMode(mode); } }
2.3.3 曲线展示
/** * 展示曲线 * * @param dataList 数据集合 * @param name 曲线名称 * @param color 曲线颜色 */ public void showLineChart(List<IncomeBean> dataList, String name, int color) { List<Entry> entries = new ArrayList<>(); for (int i = 0; i < dataList.size(); i++) { IncomeBean data = dataList.get(i); /** * 在此可查看 Entry构造方法,可发现 可传入数值 Entry(float x, float y) * 也可传入Drawable, Entry(float x, float y, Drawable icon) 可在XY轴交点 设置Drawable图像展示 */ Entry entry = new Entry(i, (float) data.getValue()); entries.add(entry); } // 每一个LineDataSet代表一条线 LineDataSet lineDataSet = new LineDataSet(entries, name); initLineDataSet(lineDataSet, color, LineDataSet.Mode.LINEAR); LineData lineData = new LineData(lineDataSet); lineChart.setData(lineData); }
然后在Activity中调用
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_line_chart); lineChart = findViewById(R.id.lineChart); initChart(lineChart); LineChartBean lineChartBean = LocalJsonAnalyzeUtil.JsonToObject(this, "chart.json", LineChartBean.class); List<IncomeBean> list = lineChartBean.getGRID0().getResult().getClientAccumulativeRate(); showLineChart(list, "我的收益", Color.CYAN); }
注意:不了解数据怎么来的可查看 相关文章:Android访问assets本地Json文件 或者本文相关代码
此时的图形效果
线性图是有了,但离需要达到的效果差了很多很多,所有需要一点点的完善。
3.曲线完善
首先总结哪里需要进行修改完善,然后一一进行修改,需要的修改的地方如下。
- 图表背景、边框、网格的修改
- X Y轴值的自定义
- 线条的渐变背景、值、点 的修改
- MarkerView的实现
- X轴的位置、X Y 轴的刻度展示(需要修改源码、放最后来处理)
3.1 图表背景、边框、网格线修改
修改背景,去掉边框
lineChart.setBackgroundColor(Color.WHITE); //是否显示边界 lineChart.setDrawBorders(false);
网格线修改
在2.3.1步的我们已经设置了禁止显示网格线
//是否展示网格线 lineChart.setDrawGridBackground(false);
但还是显示了网格线,而且不是我们想要的 虚线 。其实那是 X Y轴自己的网格线,禁掉即可
xAxis.setDrawGridLines(false); rightYaxis.setDrawGridLines(false); leftYAxis.setDrawGridLines(true);
设置X Y轴网格线为虚线(实体线长度、间隔距离、偏移量:通常使用 0)
leftYAxis.enableGridDashedLine(10f, 10f, 0f);
目标效果图没有右侧Y轴,所以去掉右侧Y轴
rightYaxis.setEnabled(false);
现在的效果图
3.2 X Y轴值的自定义
目标图的效果是 X轴显示日期,Y轴显示百分比而且均分10份
数据获取到的时间为 20180502 我们需要显示 05-02 所以需要进行日期转换
一个日期转换工具
public class DateUtil { public static String formatDate(String str) { SimpleDateFormat sf1 = new SimpleDateFormat("yyyyMMdd"); SimpleDateFormat sf2 = new SimpleDateFormat("MM-dd"); String formatStr = ""; try { formatStr = sf2.format(sf1.parse(str)); } catch (ParseException e) { e.printStackTrace(); } return formatStr; } }
X轴值的定义
在 showLineChart 方法中我们会传入X轴的值,所以自定义X轴的值可以 写在该方法内
xAxis.setValueFormatter(new IAxisValueFormatter() { @Override public String getFormattedValue(float value, AxisBase axis) { String tradeDate = dataList.get((int) value % dataList.size()).getTradeDate(); return DateUtil.formatDate(tradeDate); } });
注:目标图的数据是5月2日到5月28日,而本文所使用的数据是5月2日至5月25日。且数据日期是不包含周末的
X轴的间隔的实现,数据一共有18条,目标图是按照3天一间隔(因为无周末数据的关系,日期上看可能不是那样)
设置X轴分割数量
xAxis.setLabelCount(6,false);
true代表强制均分,可能会导致数据显示不均匀
Y轴值的自定义
与X轴值得自定义类似,并按照目标图的分割要求一样 将Y轴分为 8份
leftYAxis.setValueFormatter(new IAxisValueFormatter() { @Override public String getFormattedValue(float value, AxisBase axis) { return ((int) (value * 100)) + "%"; } }); leftYAxis.setLabelCount(8);
然后此时的效果
3.3 线条的渐变背景、值、点的修改
线条渐变线
新建一个方法
/** * 设置线条填充背景颜色 * * @param drawable */ public void setChartFillDrawable(Drawable drawable) { if (lineChart.getData() != null && lineChart.getData().getDataSetCount() > 0) { LineDataSet lineDataSet = (LineDataSet) lineChart.getData().getDataSetByIndex(0); //避免在 initLineDataSet()方法中 设置了 lineDataSet.setDrawFilled(false); 而无法实现效果 lineDataSet.setDrawFilled(true); lineDataSet.setFillDrawable(drawable); lineChart.invalidate(); } }
然后 drawable 文件中 创建渐变样式 fade_blue.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <gradient android:angle="90" android:endColor="#FF6FA9E1" android:startColor="#00ff0000" /> </shape>
再调用该方法
showLineChart(list, "我的收益", getResources().getColor(R.color.blue)); Drawable drawable = getResources().getDrawable(R.drawable.fade_blue); setChartFillDrawable(drawable);
线条点和值的更改
不显示点,在 initLineDataSet方法中添加
lineDataSet.setDrawCircles(false);
线条值的更改
目标图的效果是不显示 值,但有时候还是会要求显示值,而且还要求更高 线条X值的显示内容
所以在此介绍一下更改 曲线显示自定义X值的内容
lineDataSet.setValueFormatter(new IValueFormatter() { @Override public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) { DecimalFormat df = new DecimalFormat(".00"); return df.format(value * 100) + "%"; } });
会发现只要是自定义 值的显示内容 都是Chart对应的部分.setValueFormatter()。
现在的效果(修改了宽高)
不显示值
lineDataSet.setDrawValues(false);
3.4 MarkerView的实现
要求是点击曲线的点,然后弹出一个View 显示当前的日期,以及我的收益
即 MarkView 显示X Y 轴的值
1.搭建MarkView的布局文件 layout_markview
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/shape_square" android:orientation="vertical"> <TextView android:id="@+id/tv_date" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@android:color/white" /> <TextView android:id="@+id/tv_value" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:textColor="@android:color/white" /> </LinearLayout>其中背景 shape_square.xml 是圆角透明灰背景
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <corners android:radius="5dp" /> <stroke android:width="1px" android:color="@color/transparent_gray" /> <solid android:color="@color/transparent_gray" /> <padding android:bottom="5dp" android:left="5dp" android:right="5dp" android:top="5dp" /> </shape>
public class LineChartMarkView extends MarkerView { private TextView tvDate; private TextView tvValue; private IAxisValueFormatter xAxisValueFormatter; DecimalFormat df = new DecimalFormat(".00"); public LineChartMarkView(Context context, IAxisValueFormatter xAxisValueFormatter) { super(context, R.layout.layout_markview); this.xAxisValueFormatter = xAxisValueFormatter; tvDate = findViewById(R.id.tv_date); tvValue = findViewById(R.id.tv_value); } @SuppressLint("SetTextI18n") @Override public void refreshContent(Entry e, Highlight highlight) { //展示自定义X轴值 后的X轴内容 tvDate.setText(xAxisValueFormatter.getFormattedValue(e.getX(), null)); tvValue.setText("我的收益:" + df.format(e.getY() * 100) + "%"); super.refreshContent(e, highlight); } @Override public MPPointF getOffset() { return new MPPointF(-(getWidth() / 2), -getHeight()); } }
注:这种方式是显示自定义X轴值后的 x轴内容,只是靠e.getX()得到的float类型,无法满足我们的要求
3.设置MarkView
/** * 设置 可以显示X Y 轴自定义值的 MarkerView */ public void setMarkerView() { LineChartMarkView mv = new LineChartMarkView(this, xAxis.getValueFormatter()); mv.setChartView(lineChart); lineChart.setMarker(mv); lineChart.invalidate(); }
调用该方法即可
此时的效果
3.5 X轴的位置调整、以及X Y 轴的刻度显示
X Y 轴的刻度显示,以及位置调整可查看我的另一篇文章
相关文章:Android图表控件MPAndroidChart——LineChart实现 X、Y轴以及原点线的直尺刻度样式
发现图表的右下角还有一个描述标签 Descripition Lable 需要在LineChart初始化时设置一下
Description description = new Description(); // description.setText("需要展示的内容"); description.setEnabled(false); lineChart.setDescription(description);
此时的效果
四. 多条曲线
当前只是实现了展示一条曲线,而目标图需要实现两条(多条曲线)
4.1 LineChart创建多条曲线
前面说过 一个LineDataSet就是一条曲线,需要两条曲线的时候 在创建一个LineDataSet 添加进去即可
/** * 添加曲线 */ private void addLine(List<CompositeIndexBean> dataList, String name, int color) { List<Entry> entries = new ArrayList<>(); for (int i = 0; i < dataList.size(); i++) { CompositeIndexBean data = dataList.get(i); Entry entry = new Entry(i, (float) data.getRate()); entries.add(entry); } // 每一个LineDataSet代表一条线 LineDataSet lineDataSet = new LineDataSet(entries, name); initLineDataSet(lineDataSet, color, LineDataSet.Mode.LINEAR); lineChart.getLineData().addDataSet(lineDataSet); lineChart.invalidate(); }
然后调用改方法即可,也可以在 showLineChart方法中 创建两条曲线。
showLineChart(list, "我的收益", getResources().getColor(R.color.blue)); List<CompositeIndexBean> indexBeanList = lineChartBean.getGRID0().getResult().getCompositeIndexShanghai(); addLine(indexBeanList, "上证指数", getResources().getColor(R.color.orange));
此时的效果
4.2 MarkerView显示所以曲线的X Y 轴值
现在两条曲线了,前面MarkerView只是显示的 我的收益 的数据。现在需要显示所有曲线的的值
也就是在MarkerView 的 refreshContent中需要获取到我们展示的数据。
两种方式可以实现:
一:通过MarkerView构造方法 传入我们所展示的数据的集合
二:通过MarkerView 获取到当前的LineChart,然后通过LineChart获取LineData,图表展示的数据 都在LineData中可以得到
采用方式二比较方便,代码如下:
public class LineChartMarkView extends MarkerView { private TextView tvDate; private TextView tvValue0; private TextView tvValue1; private IAxisValueFormatter xAxisValueFormatter; DecimalFormat df = new DecimalFormat("0.00"); public LineChartMarkView(Context context, IAxisValueFormatter xAxisValueFormatter) { super(context, R.layout.layout_markview); this.xAxisValueFormatter = xAxisValueFormatter; tvDate = (TextView) findViewById(R.id.tv_date); tvValue0 = (TextView) findViewById(R.id.tv_value0); tvValue1 = (TextView) findViewById(R.id.tv_value1); } @SuppressLint("SetTextI18n") @Override public void refreshContent(Entry e, Highlight highlight) { Chart chart = getChartView(); if (chart instanceof LineChart) { LineData lineData = ((LineChart) chart).getLineData(); //获取到图表中的所有曲线 List<ILineDataSet> dataSetList = lineData.getDataSets(); for (int i = 0; i < dataSetList.size(); i++) { LineDataSet dataSet = (LineDataSet) dataSetList.get(i); //获取到曲线的所有在Y轴的数据集合,根据当前X轴的位置 来获取对应的Y轴值 float y = dataSet.getValues().get((int) e.getX()).getY(); if (i == 0) { tvValue0.setText(dataSet.getLabel() + ":" + df.format(y * 100) + "%"); } if (i == 1) { tvValue1.setText(dataSet.getLabel() + ":" + df.format(y * 100) + "%"); } } tvDate.setText(xAxisValueFormatter.getFormattedValue(e.getX(), null)); } super.refreshContent(e, highlight); } @Override public MPPointF getOffset() { return new MPPointF(-(getWidth() / 2), -getHeight()); } }
此时的图表
五. 重置某条曲线
经过前面的几步图表是基本完成了,就差底部的切换按钮以及曲线重置了。
布局代码在此就不展示了,详细代码请看文本 本文相关代码。在此列出重置曲线方法的代码
public void resetLine(int position, List<CompositeIndexBean> dataList, String name, int color) { LineData lineData = lineChart.getData(); List<ILineDataSet> list = lineData.getDataSets(); if (list.size() <= position) { return; } List<Entry> entries = new ArrayList<>(); for (int i = 0; i < dataList.size(); i++) { CompositeIndexBean data = dataList.get(i); Entry entry = new Entry(i, (float) data.getRate()); entries.add(entry); } LineDataSet lineDataSet = new LineDataSet(entries, name); initLineDataSet(lineDataSet, color, LineDataSet.Mode.LINEAR); lineData.getDataSets().set(position, lineDataSet); lineChart.invalidate(); }
调用该方法,将第二条曲线设置为深证指数
shenzheng = lineChartBean.getGRID0().getResult().getCompositeIndexShenzhen(); resetLine(1, shenzheng, "深证指数", getResources().getColor(R.color.orange));
设置不显示曲线名称(图例)Legend
legend.setEnabled(false);
最终效果
本文代码:https://github.com/897532167/ChartManager
绘制刻度线:Android图表控件MPAndroidChart——LineChart实现 X、Y轴以及原点线的直尺刻度样式