欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android实现价格走势自定义曲线图

程序员文章站 2022-05-20 21:55:58
本文是引用开源图表库框架 mpandroidchart的linechart 地址:https://github.com/philjay/mpandroidchart...

本文是引用开源图表库框架 mpandroidchart的linechart

地址:https://github.com/philjay/mpandroidchart

1.需求:

(1)动态添加radiobutton,点击改变下面的linechart数据

(2)linechart绘制价格走势图,只显示最低点的小圆点和view,手指滑动,markview数据变化。

(3) 服务端返回端数据,不是每一天端数据,但是x轴显示的必须是每一天的数据,这里是有我自己处理过的。返回里需要显示点的数组,之前的时间点显示的就是第一个点值。

Android实现价格走势自定义曲线图

2.实现效果:

Android实现价格走势自定义曲线图

最低点显示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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。