Android 價格走勢曲線圖

本文是引用開源圖表庫框架 MPAndroidChart的LineChart
地址:https://github.com/PhilJay/MPAndroidChart
1.需求:
(1)動態(tài)添加RadioButton舅巷,點(diǎn)擊改變下面的LineChart數(shù)據(jù)
(2)LineChart繪制價格走勢圖疏咐,只顯示最低點(diǎn)的小圓點(diǎn)和View,手指滑動班利,MarkView數(shù)據(jù)變化。
(3) 服務(wù)端返回端數(shù)據(jù)锹安,不是每一天端數(shù)據(jù),但是x軸顯示的必須是每一天的數(shù)據(jù)器净,這里是有我自己處理過的尖淘。返回里需要顯示點(diǎn)的數(shù)組,之前的時間點(diǎn)顯示的就是第一個點(diǎn)值倡勇。


2.實(shí)現(xiàn)效果:

最低點(diǎn)顯示View和小圓點(diǎn)是自定義的逞刷,通過修改 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初始化,數(shù)據(jù)的處理,已經(jīng)手勢的一些操作
簡單的說一下思路夸浅,因?yàn)?Linechart的x,y都是自定義的仑最,但是我這里只自定義的y軸,是把x隱藏起來的帆喇,x軸只顯示最開始的點(diǎn)和結(jié)束的點(diǎn)警医,所以我這里有點(diǎn)投機(jī),自己設(shè)置點(diǎn)兩個textview來顯示的
Linechart的點(diǎn)一設(shè)置都是統(tǒng)一所有點(diǎn)都設(shè)置的坯钦,但是需求上是得只在最低點(diǎn)顯示预皇,并還要繪制一個view先初始化 View,然后解析數(shù)據(jù),

  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());
        }

再根據(jù)解析的數(shù)據(jù)動態(tài)添加RadioButton
初始化LineChart

private void initLineChar() {
        List<JsonData.HistoricalPrice.HistoricalPriceData.DataList> datalist
                = removeDuplicteData(mHistoricalPrice.getData_list());
        //設(shè)置手勢滑動事件
        mLineChar.setOnChartGestureListener(this);
        //設(shè)置數(shù)值選擇監(jiān)聽
        mLineChar.setOnChartValueSelectedListener(this);
        //后臺繪制
        mLineChar.setDrawGridBackground(false);
        //設(shè)置描述文本
        mLineChar.getDescription().setEnabled(false);
        mLineChar.setTouchEnabled(true); // 設(shè)置是否可以觸摸
        mLineChar.setDragEnabled(true);// 是否可以拖拽
        mLineChar.setScaleXEnabled(true); //是否可以縮放 僅x軸
        mLineChar.setScaleYEnabled(true); //是否可以縮放 僅y軸
        mLineChar.setPinchZoom(true);  //設(shè)置x軸和y軸能否同時縮放婉刀。默認(rèn)是否

        mLineChar.setDragDecelerationFrictionCoef(0.99f);
        mLineChar.getAxisRight().setEnabled(false);
        // 默認(rèn)動畫
        mLineChar.animateX(2500);

        setMakeList(removeDuplicteData(datalist));
        initMark(makeList, Long.valueOf(mHistoricalPrice.getStart_time()));
        initXAxis(datalist.size(), xAxisValuesStr);
        initYAxis();
        initLegend();
        setLineCharData(makeList);
    }

設(shè)置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();
        }

    }

這里是設(shè)置LineChart里面的數(shù)據(jù)

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 {
            // 創(chuàng)建一個數(shù)據(jù)集,并給它一個類型
            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); // 取消點(diǎn)擊線上的點(diǎn)展示十字標(biāo)識
                set1.setDrawValues(true); // 不展示線上面點(diǎn)的值
                //是否顯示小圓點(diǎn)
                set1.setDrawCircles(false);
                //修改源碼 自定義的參數(shù)吟温,可以顯示最低點(diǎn)的View
                set1.setLowDrawCircles(true);
                set1.setCircleColors(Color.rgb(27, 198, 181));//27, 198, 181
                //頂點(diǎn)設(shè)置值
                set1.setDrawValues(false);
                set1.setFillColor(Color.rgb(203, 242, 238));
            }
            //修改源碼 自定義的參數(shù),可以顯示最低點(diǎn)的View
            set1.setLowNumbers(minData);
            ArrayList<ILineDataSet> dataSets = new ArrayList<ILineDataSet>();
            //添加數(shù)據(jù)集
            dataSets.add(set1);
            //創(chuàng)建一個數(shù)據(jù)集的數(shù)據(jù)對象
            LineData data = new LineData(dataSets);
            //設(shè)置數(shù)據(jù)
            mLineChar.setData(data);
        }
    }

這里是在源碼里新加的地方

 //修改源碼 自定義的參數(shù)突颊,可以顯示最低點(diǎn)的View     
 set1.setLowDrawCircles(true);    
 set1.setLowNumbers(minData);

源碼修改部分:
1.在LineDataSet添加2個參數(shù)鲁豪,復(fù)寫ILineDataSet新加的方法

 //是否顯示最低點(diǎn)的小圓點(diǎn)

 private boolean mDrawLowCircle = false;

 //最低點(diǎn)對應(yīng)的具體值

  private float mLowNumbers = 100f;
   

2.在ILineDataSet接口中添加2個方法

boolean isLowDrawCirclesEnabled();

float getLowNumbers();

3.修改源碼LineChartRenderer這個類的 drawValues(Canvas c)方法中,這里是設(shè)置最低點(diǎn)顯示的View,這個方法中添加判斷:

//設(shè)置最低點(diǎn)顯示的自定義view
if (dataSet.isLowDrawCirclesEnabled()) {
    if (entry.getY() == dataSet.getYMin()) {
        //設(shè)置在左邊
        if (x < 100) {
            locationcode = 1;
        } else {   // 默認(rèn)在右邊
            locationcode = 0;
        }
        appCustomDrawValue(c, dataSet.getValueFormatter(), entry.getY(), entry, i, x,
                y - valOffset, Color.WHITE);
        break;
    }
}

private int locationcode = 0;
//設(shè)置最低點(diǎn)顯示的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)方法中添加判斷:則可以顯示最低點(diǎn)的小圓點(diǎn)了律秃。

//顯示最低點(diǎn)的小圓點(diǎn)
if (dataSet.isLowDrawCirclesEnabled()) {
    if (e.getY() == dataSet.getYMin()) {
        Bitmap circleBitmap = imageCache.getBitmap(j);
        c.drawBitmap(circleBitmap, mCirclesBuffer[0] - circleRadius, mCirclesBuffer[1] - circleRadius, null);
        break;

    }

}

好了爬橡,所有功能的關(guān)鍵部分已經(jīng)講完了。大家不懂的可以留言提問友绝,或者自己下載源碼看看:
源碼地址:
https://github.com/Songyan992/LineChartStudy

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末堤尾,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子迁客,更是在濱河造成了極大的恐慌郭宝,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掷漱,死亡現(xiàn)場離奇詭異粘室,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)卜范,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進(jìn)店門衔统,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人海雪,你說我怎么就攤上這事锦爵。” “怎么了奥裸?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵险掀,是天一觀的道長。 經(jīng)常有香客問我湾宙,道長樟氢,這世上最難降的妖魔是什么冈绊? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮埠啃,結(jié)果婚禮上死宣,老公的妹妹穿的比我還像新娘。我一直安慰自己碴开,他們只是感情好毅该,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著潦牛,像睡著了一般鹃骂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上罢绽,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天,我揣著相機(jī)與錄音静盅,去河邊找鬼良价。 笑死,一個胖子當(dāng)著我的面吹牛蒿叠,可吹牛的內(nèi)容都是我干的明垢。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼市咽,長吁一口氣:“原來是場噩夢啊……” “哼痊银!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起施绎,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤溯革,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后谷醉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體致稀,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年俱尼,在試婚紗的時候發(fā)現(xiàn)自己被綠了抖单。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡遇八,死狀恐怖矛绘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情刃永,我是刑警寧澤货矮,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站揽碘,受9級特大地震影響次屠,放射性物質(zhì)發(fā)生泄漏园匹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一劫灶、第九天 我趴在偏房一處隱蔽的房頂上張望裸违。 院中可真熱鬧,春花似錦本昏、人聲如沸供汛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽怔昨。三九已至,卻和暖如春宿稀,著一層夾襖步出監(jiān)牢的瞬間趁舀,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工祝沸, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留矮烹,地道東北人。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓罩锐,卻偏偏與公主長得像奉狈,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子涩惑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容