Android实现价格走势自定义曲线图
本文是引用开源图表库框架 mpandroidchart的linechart
地址:https://github.com/philjay/mpandroidchart
1.需求:
(1)动态添加radiobutton,点击改变下面的linechart数据
(2)linechart绘制价格走势图,只显示最低点的小圆点和view,手指滑动,markview数据变化。
(3) 服务端返回端数据,不是每一天端数据,但是x轴显示的必须是每一天的数据,这里是有我自己处理过的。返回里需要显示点的数组,之前的时间点显示的就是第一个点值。
2.实现效果:
最低点显示view和小圆点是自定义的,通过修改 linechart的源码,下面我们来具体分析代码
3.代码分析
(1)布局的xml
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <radiogroup android:id="@+id/mradiogroup" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margintop="30px" android:orientation="horizontal" android:visibility="gone"> </radiogroup> <linearlayout android:layout_width="match_parent" android:layout_height="200dp" android:orientation="vertical"> <com.github.mikephil.charting.charts.linechart android:id="@+id/mlinechart" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" /> <linearlayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <textview android:id="@+id/detailmintimetv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginleft="50px" android:layout_weight="1" android:textcolor="#b5b5b5" android:textsize="24px" /> <textview android:id="@+id/detailmaxtimetv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginright="30px" android:layout_weight="1" android:gravity="right" android:textcolor="#b5b5b5" android:textsize="24px" /> </linearlayout> </linearlayout> </linearlayout>
这里主要是添加以一个radiogroup和一个linechart
接下来是mainactivity.class
private void addviewforgroup(final list<jsondata.historicalprice> list) { for (int i = 0; i < list.size(); i++) { final radiobutton view = (radiobutton) layoutinflater.from(mainactivity.this) .inflate(r.layout.item_gr_add_but_layout, mradiogroup, false); view.setid(i); view.settext(list.get(i).gettitle()); if (i==0){ view.performclick(); radiogrouptextchange(list.get(0).getdata(), list.get(0).gettitle()); mlinecharwidget = new linechartwidget(mainactivity.this, list.get(0).getdata(), mlinechart, setminprice(list.get(0).getdata())); } mradiogroup.addview(view); } mradiogroup.setoncheckedchangelistener(new radiogroup.oncheckedchangelistener() { @override public void oncheckedchanged(radiogroup group, int checkedid) { radiobutton button = (radiobutton) findviewbyid(checkedid); button.settext(list.get(checkedid).gettitle()); for (int i = 0; i < list.size(); i++) { if (button.gettext().tostring().equals(list.get(i).gettitle())) { radiogrouptextchange(list.get(i).getdata(), list.get(i).gettitle()); if (mlinecharwidget == null) { mlinecharwidget = new linechartwidget(mainactivity.this, list.get(i).getdata(), mlinechart, setminprice(list.get(i).getdata())); } else { mlinecharwidget.updatelinechar(list.get(i).getdata(), setminprice(list.get(i).getdata())); } } } } }); }
注意:这里的linechartwidget是我自己封装的一个linechart,包括linechart初始化,数据的处理,已经手势的一些操作
简单的说一下思路,因为 linechart的x,y都是自定义的,但是我这里只自定义的y轴,是把x隐藏起来的,x轴只显示最开始的点和结束的点,所以我这里有点投机,自己设置点两个textview来显示的
linechart的点一设置都是统一所有点都设置的,但是需求上是得只在最低点显示,并还要绘制一个view先初始化 view,然后解析数据,
jsondata jsondetail = new gson().fromjson(jsonstr.tostring(), new typetoken<jsondata>() { }.gettype()); if (jsondetail.gethistorical_price() != null && jsondetail.gethistorical_price().size() > 0) { setgrouplay(jsondetail.gethistorical_price()); }
再根据解析的数据动态添加radiobutton
初始化linechart
private void initlinechar() { list<jsondata.historicalprice.historicalpricedata.datalist> datalist = removeduplictedata(mhistoricalprice.getdata_list()); //设置手势滑动事件 mlinechar.setonchartgesturelistener(this); //设置数值选择监听 mlinechar.setonchartvalueselectedlistener(this); //后台绘制 mlinechar.setdrawgridbackground(false); //设置描述文本 mlinechar.getdescription().setenabled(false); mlinechar.settouchenabled(true); // 设置是否可以触摸 mlinechar.setdragenabled(true);// 是否可以拖拽 mlinechar.setscalexenabled(true); //是否可以缩放 仅x轴 mlinechar.setscaleyenabled(true); //是否可以缩放 仅y轴 mlinechar.setpinchzoom(true); //设置x轴和y轴能否同时缩放。默认是否 mlinechar.setdragdecelerationfrictioncoef(0.99f); mlinechar.getaxisright().setenabled(false); // 默认动画 mlinechar.animatex(2500); setmakelist(removeduplictedata(datalist)); initmark(makelist, long.valueof(mhistoricalprice.getstart_time())); initxaxis(datalist.size(), xaxisvaluesstr); inityaxis(); initlegend(); setlinechardata(makelist); }
设置markview
private void setmakelist(list<jsondata.historicalprice.historicalpricedata.datalist> datalist) { try { simpledateformat format = new simpledateformat("yyyy-mm-dd hh:mm:ss"); date dbegin = format.parse(format.format(long.valueof(mhistoricalprice.getstart_time()) * 1000)); date dend = format.parse(format.format(long.valueof(mhistoricalprice.getend_time()) * 1000)); float prices = 0; list<date> listdate = getdatesbetweentwodate(dbegin, dend); if (datalist.size() >= listdate.size()) { makelist.clear(); makelist.addall(datalist); } else { for (int i = 0; i < listdate.size(); i++) { jsondata.historicalprice.historicalpricedata.datalist data = new jsondata.historicalprice.historicalpricedata.datalist(); for (int j = 0; j < datalist.size(); j++) { if (timetostring(datetotimestamp(listdate.get(i))).equals(timetostring(long.valueof(datalist.get(j).getprice_drop_time())))) { data.setprice_drop_time(datalist.get(j).getprice_drop_time()); data.setprice_new(datalist.get(j).getprice_new()); prices = (datalist.get(j).getprice_new()); } else { data.setprice_drop_time(datetotimestamp(listdate.get(i)) + ""); data.setprice_new(prices); } } makelist.add(data); } } } catch (parseexception e) { e.printstacktrace(); } }
这里是设置linechart里面的数据
private void setdata(arraylist<entry> values) { linedataset set1 = null; if (mlinechar.getdata() != null && mlinechar.getdata().getdatasetcount() > 0) { set1 = (linedataset) mlinechar.getdata().getdatasetbyindex(0); set1.setvalues(values); mlinechar.getdata().notifydatachanged(); mlinechar.notifydatasetchanged(); } else { // 创建一个数据集,并给它一个类型 if (set1 == null) { set1 = new linedataset(values, "价格曲线图"); set1.setcolor(color.rgb(27, 198, 181)); set1.setcirclecolor(color.black); set1.setlinewidth(1f); set1.setcircleradius(3f); set1.setdrawcirclehole(false); set1.setvaluetextsize(9f); set1.setdrawfilled(true); set1.setformlinewidth(1f); set1.setformlinedasheffect(new dashpatheffect(new float[]{10f, 5f}, 0f)); set1.sethighlightenabled(true); //允许突出显示dataset set1.setdrawhighlightindicators(false); // 取消点击线上的点展示十字标识 set1.setdrawvalues(true); // 不展示线上面点的值 //是否显示小圆点 set1.setdrawcircles(false); //修改源码 自定义的参数,可以显示最低点的view set1.setlowdrawcircles(true); set1.setcirclecolors(color.rgb(27, 198, 181));//27, 198, 181 //顶点设置值 set1.setdrawvalues(false); set1.setfillcolor(color.rgb(203, 242, 238)); } //修改源码 自定义的参数,可以显示最低点的view set1.setlownumbers(mindata); arraylist<ilinedataset> datasets = new arraylist<ilinedataset>(); //添加数据集 datasets.add(set1); //创建一个数据集的数据对象 linedata data = new linedata(datasets); //设置数据 mlinechar.setdata(data); } }
这里是在源码里新加的地方
//修改源码 自定义的参数,可以显示最低点的view set1.setlowdrawcircles(true); set1.setlownumbers(mindata);
源码修改部分:
1.在linedataset添加2个参数,复写ilinedataset新加的方法
//是否显示最低点的小圆点 private boolean mdrawlowcircle = false; //最低点对应的具体值 private float mlownumbers = 100f;
2.在ilinedataset接口中添加2个方法
boolean islowdrawcirclesenabled(); float getlownumbers();
3.修改源码linechartrenderer这个类的 drawvalues(canvas c)方法中,这里是设置最低点显示的view,这个方法中添加判断:
//设置最低点显示的自定义view if (dataset.islowdrawcirclesenabled()) { if (entry.gety() == dataset.getymin()) { //设置在左边 if (x < 100) { locationcode = 1; } else { // 默认在右边 locationcode = 0; } appcustomdrawvalue(c, dataset.getvalueformatter(), entry.gety(), entry, i, x, y - valoffset, color.white); break; } } private int locationcode = 0; //设置最低点显示的text和text的背景框 private void appcustomdrawvalue(canvas c, ivalueformatter formatter, float value, entry entry, int datasetindex, float x, float y, int color) { // paint.fontmetrics fm = new paint.fontmetrics(); mvaluepaint.setcolor(color.rgb(27, 198, 181)); // mvaluepaint.getfontmetrics(fm); y = (y + utils.convertdptopixel(30)); switch (locationcode) { case 0: rectf rectf = new rectf((x - utils.convertdptopixel(35)), (y - utils.convertdptopixel(23)), (x + utils.convertdptopixel(5)), y); c.drawroundrect(rectf, 10, 10, mvaluepaint); mvaluepaint.setcolor(color); c.drawtext("¥" + formatter.getformattedvalue(value, entry, datasetindex, mviewporthandler), x - utils.convertdptopixel(15), y - utils.convertdptopixel(10), mvaluepaint); break; case 1: rectf rectf1 = new rectf(x + utils.convertdptopixel(5), (y - utils.convertdptopixel(23)), x + utils.convertdptopixel(45), y); c.drawroundrect(rectf1, 10, 10, mvaluepaint); mvaluepaint.setcolor(color); c.drawtext("¥" + formatter.getformattedvalue(value, entry, datasetindex, mviewporthandler), x + utils.convertdptopixel(27), y - utils.convertdptopixel(10), mvaluepaint); break; } }
在drawcircles(canvas c)方法中添加判断:则可以显示最低点的小圆点了。
//显示最低点的小圆点 if (dataset.islowdrawcirclesenabled()) { if (e.gety() == dataset.getymin()) { bitmap circlebitmap = imagecache.getbitmap(j); c.drawbitmap(circlebitmap, mcirclesbuffer[0] - circleradius, mcirclesbuffer[1] - circleradius, null); break; } }
好了,所有功能的关键部分已经讲完了。大家不懂的可以留言提问,或者自己下载源码看看:
github项目地址:https://github.com/songyan992/linechartstudy
源码下载地址:linechartstudy_jb51.rar
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。