Android绘制价格走势曲线图

需求

(1)、动态添加RadioButton,点击改变下面的LineChart数据

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

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

效果图

最低点显示View和小圆点是自定义的,通过修改 LineChart的源码,下面我们来具体分析代码。

代码分析

布局的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;
    }
}

本文是引用开源图表库框架 MPAndroidChart的LineChart,地址:

https: //github.com/Songyan992/LineChartStudy
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

金戈鐡馬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值