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

作者:一花一朝 时间:2023-04-03 23:15:06 

本文是引用开源图表库框架 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;

}

}

来源:http://www.jianshu.com/p/3d15baa6682a#

标签:android,曲线图
0
投稿

猜你喜欢

  • Android亮屏速度分析总结

    2023-11-06 11:55:21
  • hibernate-validator如何使用校验框架

    2023-05-25 07:26:29
  • windows下jar包开机自动重启的步骤

    2022-10-17 22:21:41
  • 详解SpringBoot 快速整合Mybatis(去XML化+注解进阶)

    2022-02-19 03:54:29
  • Java性能调优概述

    2023-07-06 05:42:51
  • java实现通过绑定邮箱找回密码功能

    2021-12-17 00:16:48
  • 基于JAVA文件中获取路径及WEB应用程序获取路径的方法

    2022-08-21 01:26:57
  • flutter中的资源和图片加载示例详解

    2023-08-24 13:19:39
  • C#中事件处理的个人体会

    2023-11-02 02:14:39
  • c# 动态加载dll文件,并实现调用其中的方法(推荐)

    2021-11-10 04:37:34
  • Android异步回调中的UI同步性问题分析

    2022-07-31 14:10:51
  • 用C#编写ActiveX控件(三)

    2023-03-26 12:35:10
  • java ReentrantLock条件锁实现原理示例详解

    2023-12-12 02:36:13
  • SpringBoot实现MapperScan添加动态配置(占位符)

    2023-11-26 05:08:06
  • Java设计模式之抽象工厂模式浅析讲解

    2022-08-08 18:26:47
  • Java利用apache ftp工具实现文件上传下载和删除功能

    2022-03-17 02:04:01
  • Java 六类运算符详解

    2023-08-27 20:37:37
  • Java静态代理和动态代理的深入讲解

    2023-04-12 03:07:33
  • 使用@RequestParam设置默认可以传空值

    2023-07-01 08:34:57
  • 解决RestTemplate加@Autowired注入不了的问题

    2022-07-14 03:00:48
  • asp之家 软件编程 m.aspxhome.com