基于MPAndroidChart的自定義LineChart(二)----添加單擊事件的處理

上一篇文章基于MPAndroidChart的自定義LineChart(一)----節(jié)點(diǎn)繪制叉號+分段繪制背景中添加了節(jié)點(diǎn)繪制叉號+分段繪制背景的功能蟹腾,這篇文章繼續(xù)改造,給MPAndroidChart的LineChart單擊事件做一些處理更舞,讓圖表能跟響應(yīng)單擊操作刽射,改變數(shù)據(jù)重繪圖表览绿。

效果如下:

每次單擊圖表窿祥,對應(yīng)的數(shù)據(jù)都會(huì)改變,圖表也會(huì)重新繪制

功能實(shí)現(xiàn)

由于MPAndroiChart只支持縮放庇麦、拖動(dòng)(平移)计技、選擇等手勢,但這些手圖表的數(shù)據(jù)沒有什么改變山橄,如果我們需要在圖標(biāo)上根據(jù)手勢修改數(shù)據(jù)垮媒,繼而重繪圖表,就需要自己處理了。好在MPAndroiChart為我們提供了OnChartGestureListener和OnChartValueSelectedListener兩個(gè)接口供我們處理手勢睡雇。

OnChartGestureListener

public interface OnChartGestureListener {

    void onChartGestureStart(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture);
    
    void onChartGestureEnd(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture);

    void onChartLongPressed(MotionEvent me);

    void onChartDoubleTapped(MotionEvent me);

    void onChartSingleTapped(MotionEvent me);

    void onChartFling(MotionEvent me1, MotionEvent me2, float velocityX, float velocityY);

    void onChartScale(MotionEvent me, float scaleX, float scaleY);

    void onChartTranslate(MotionEvent me, float dX, float dY);
}

從方法名就能看出在什么時(shí)候背調(diào)用了

OnChartValueSelectedListener

public interface OnChartValueSelectedListener {

    void onValueSelected(Entry e, Highlight h);

    void onNothingSelected();
}

onValueSelected是圖表中的某一個(gè)值被選擇后被調(diào)用萌衬,但是并不是說一定要點(diǎn)在節(jié)點(diǎn)的圓環(huán)那里才會(huì)被選中,而是把圖表分為一段一段它抱,如下圖所示:


點(diǎn)擊整列的任何位置都會(huì)調(diào)用onValueSelected方法秕豫。

繼承Linechart,初始化

第一步還是要繼承LineChart观蓄,并進(jìn)行初始化混移。

    private void initSingleTapLineChart() {

        values = new ArrayList<>();

        this.getDescription().setEnabled(false);
        this.setTouchEnabled(false);
        this.setDragEnabled(false);
        this.setScaleEnabled(false);
        this.setPinchZoom(false);
        this.setDrawBorders(false);

        // 設(shè)置是否可以觸摸
        this.setTouchEnabled(true);
        // 監(jiān)聽觸摸事件
        this.setOnChartGestureListener(this);
        this.setOnChartValueSelectedListener(this);
        // 是否可以拖拽
        this.setDragEnabled(true);
        // 是否可以縮放
        this.setScaleEnabled(false);

    }

最重要的是設(shè)置圖表可以觸摸,可以拖拽侮穿,并添加OnChartGestureListener和OnChartValueSelectedListener兩個(gè)監(jiān)聽器歌径。

給圖表添加數(shù)據(jù)

這里我新建了一個(gè)setChartData方法,用戶將ArrayList傳進(jìn)方法亲茅,先對折線進(jìn)行配置回铛,再添加到圖表中。

    public void setChartData(ArrayList<Entry> values) {
        this.values = values;
        XAxis xAxis = this.getXAxis();
        xAxis.setAxisMinimum(-1f);
        xAxis.setAxisMaximum(9f);
        xAxis.setGranularity(1f);
        xAxis.enableGridDashedLine(10f, 10f, 0f);
        xAxis.setDrawAxisLine(false);
        xAxis.setDrawLabels(true);
        xAxis.setLabelCount(11);
        YAxis leftAxis = this.getAxisLeft();
        leftAxis.removeAllLimitLines();
        leftAxis.setAxisMaximum(80f);
        leftAxis.setAxisMinimum(10f);
        leftAxis.setGranularity(10f);
        leftAxis.enableGridDashedLine(10f, 10f, 0f);
        leftAxis.setDrawZeroLine(false);
        leftAxis.setDrawAxisLine(false);
        leftAxis.setDrawLabels(true);
        this.getAxisRight().setEnabled(false);

        Legend l = this.getLegend();
        l.setForm(Legend.LegendForm.LINE);

        LineDataSet set1 = new LineDataSet(values, "曲線");

        set1.enableDashedLine(10f, 5f, 0f);
        set1.enableDashedHighlightLine(10f, 5f, 0f);
        set1.setColor(Color.RED);
        set1.setDrawCircles(true);
        set1.setCircleColor(Color.RED);
        set1.setLineWidth(1f);
        set1.setValueTextSize(9f);
        set1.setDrawFilled(false);
        set1.setFormLineWidth(1f);
        set1.setFormLineDashEffect(new DashPathEffect(new float[]{10f, 5f}, 0f));
        set1.setFormSize(15.f);

        ArrayList<ILineDataSet> dataSets = new ArrayList<>();
        dataSets.add(set1);

        LineData data = new LineData(dataSets);
        //最后調(diào)用MPAndroidChart提供的setData方法
        this.setData(data);
    }

** 注意: ** 此方法是為了先配置折線克锣,再調(diào)用MPAndroidChart提供的setData方法茵肃。
到此時(shí)已經(jīng)可以正常的顯示一個(gè)圖表了,但還沒有加入單擊事件袭祟。

加入單擊事件

onValueSelected

在這里先獲取選中的值免姿,拿到該值的Entry,通過getX()和getY()方法取得X榕酒,Y值,再通過getPixelForValues方法獲得該值的像素坐標(biāo)點(diǎn)故俐。

    public void onValueSelected(Entry e, Highlight h) {
        // 獲取Entry
        iEntry = (int) e.getX();
        valEntry = e.getY();
        Log.i(TAG, "e.getX() = " + iEntry + "     e.getY() = " + valEntry);
        // 獲取選中value的坐標(biāo)
        MPPointD p = this.getPixelForValues(e.getX(), e.getY(), YAxis.AxisDependency.LEFT);
        xValuePos = p.x;
        yValuePos = p.y;
        Log.i(TAG, "xValuePos = " + xValuePos + "     yValuePos = " + yValuePos);
    }

onChartGestureEnd

我這里選了onChartGestureEnd方法而不是onChartSingleTapped方法想鹰,只是因?yàn)槲耶?dāng)時(shí)沒注意到第二個(gè),效果應(yīng)該一樣吧药版,嘿嘿辑舷。
先判斷手勢的類型,是不是單擊事件槽片,是的話就獲得單擊點(diǎn)的像素坐標(biāo)點(diǎn)何缓。

    public void onChartGestureEnd(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) {
        Log.i(TAG, "onChartGestureEnd, lastGesture: " + lastPerformedGesture);
        if (lastPerformedGesture == ChartTouchListener.ChartGesture.SINGLE_TAP) {
            Log.i(TAG, "SingleTapped");
            yTouchPostion = me.getY();
            changeTouchEntry();
        }
        this.highlightValues(null);
    }

到這里我們就取得了需要數(shù)據(jù)的X值,Y值还栓,原本的像素坐標(biāo)點(diǎn)和單擊處像素坐標(biāo)點(diǎn)碌廓。

最后的處理


畫了一個(gè)簡單的圖,比較好講解剩盒。
如圖谷婆,我們知道1點(diǎn)的Y值(Y1)和2點(diǎn)的Y值(Y2),同時(shí)求出了紅線的長度(redLen),那么黃線的長度(yellowLen)顯然就等于紅線長度乘以Y2比Y1的值:

yellowLen = redLen * Y2 / Y1

換到表中纪挎,我們要求的是單擊處對應(yīng)在圖表上的值期贫,即黃線長度;紅線長度是本來的Y值异袄,Y2是單擊點(diǎn)處到0坐標(biāo)點(diǎn)處的距離通砍,Y1是原來的值到0坐標(biāo)點(diǎn)處的距離。
最后刷新數(shù)據(jù)烤蜕,重繪圖表封孙。

    public void changeTouchEntry() {
        // 獲取X軸和Y軸的0坐標(biāo)的pixel值
        MPPointD p = this.getPixelForValues(0, 0, YAxis.AxisDependency.LEFT);
        double yAixs0 = p.y;
        // 修改TouchEntry的y的值
        Log.i(TAG, "計(jì)算過程");
        Log.i(TAG, "yAixs0: " + yAixs0);
        double y1 = yValuePos - yAixs0;
        double y2 = yTouchPostion - yAixs0;
        Log.i(TAG, "原來的y值所在的坐標(biāo)減0點(diǎn)");
        Log.i(TAG, "yValuePos - yAixs0: " + y1);
        Log.i(TAG, "點(diǎn)擊的y值所在的坐標(biāo)減0點(diǎn)");
        Log.i(TAG, "yTouchPostion - yAixs0: " + y2);
        valEntry = (float) (valEntry * (y2 / y1));
        Log.i(TAG, "value");
        Log.i(TAG, "X: " + iEntry + "     Y: " + valEntry);
        values.set(iEntry, new Entry(iEntry, valEntry));
        this.notifyDataSetChanged();
        this.invalidate();
}

這樣就完成了單擊事件的處理。

添加響應(yīng)接口

當(dāng)然有時(shí)候我們要對單擊事件做處理玖绿,所以再添加一個(gè)接口就行了敛瓷。

    public interface OnSingleTapListener{
        void onSingleTap(int x,float y);
    }

接口的回調(diào)我放到了重繪圖表后

this.notifyDataSetChanged();
        this.invalidate();

        if (onSingleTapListener != null){
            onSingleTapListener.onSingleTap(iEntry,valEntry);
        }

END

最后要說到一點(diǎn),我把對圖表的配置放到了自定義類里斑匪,這樣第一減少Activity內(nèi)的代碼量呐籽,提高可讀性;第二是比較方便蚀瘸,可以直接使用數(shù)據(jù)狡蝶;
第三是一個(gè)應(yīng)用中存在數(shù)個(gè)圖表時(shí),一般也會(huì)統(tǒng)一風(fēng)格贮勃,這樣寫就能提高代碼復(fù)用率了贪惹。

最后,博客里畢竟說得不詳細(xì)寂嘉,深入了解看代碼奏瞬,歡迎交流討論:
https://github.com/xiaoniu/SingleTapLineChart

想要更了解MPAndroidChart,可以參考這一個(gè)系列的博客:
MPAndroidChart 教程----莊宏基

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末泉孩,一起剝皮案震驚了整個(gè)濱河市硼端,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌寓搬,老刑警劉巖珍昨,帶你破解...
    沈念sama閱讀 216,843評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異句喷,居然都是意外死亡镣典,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,538評論 3 392
  • 文/潘曉璐 我一進(jìn)店門唾琼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來兄春,“玉大人,你說我怎么就攤上這事锡溯∩窠迹” “怎么了肴裙?”我有些...
    開封第一講書人閱讀 163,187評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長涌乳。 經(jīng)常有香客問我蜻懦,道長,這世上最難降的妖魔是什么夕晓? 我笑而不...
    開封第一講書人閱讀 58,264評論 1 292
  • 正文 為了忘掉前任宛乃,我火速辦了婚禮,結(jié)果婚禮上蒸辆,老公的妹妹穿的比我還像新娘征炼。我一直安慰自己,他們只是感情好躬贡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,289評論 6 390
  • 文/花漫 我一把揭開白布谆奥。 她就那樣靜靜地躺著,像睡著了一般拂玻。 火紅的嫁衣襯著肌膚如雪酸些。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,231評論 1 299
  • 那天檐蚜,我揣著相機(jī)與錄音魄懂,去河邊找鬼。 笑死闯第,一個(gè)胖子當(dāng)著我的面吹牛市栗,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播咳短,決...
    沈念sama閱讀 40,116評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼填帽,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了咙好?” 一聲冷哼從身側(cè)響起篡腌,我...
    開封第一講書人閱讀 38,945評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎敷扫,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體诚卸,經(jīng)...
    沈念sama閱讀 45,367評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡葵第,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,581評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了合溺。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片卒密。...
    茶點(diǎn)故事閱讀 39,754評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖棠赛,靈堂內(nèi)的尸體忽然破棺而出哮奇,到底是詐尸還是另有隱情膛腐,我是刑警寧澤,帶...
    沈念sama閱讀 35,458評論 5 344
  • 正文 年R本政府宣布鼎俘,位于F島的核電站哲身,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏贸伐。R本人自食惡果不足惜勘天,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,068評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望捉邢。 院中可真熱鬧脯丝,春花似錦、人聲如沸伏伐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,692評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽藐翎。三九已至材蹬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間阱高,已是汗流浹背赚导。 一陣腳步聲響...
    開封第一講書人閱讀 32,842評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留赤惊,地道東北人吼旧。 一個(gè)月前我還...
    沈念sama閱讀 47,797評論 2 369
  • 正文 我出身青樓,卻偏偏與公主長得像未舟,于是被迫代替她去往敵國和親圈暗。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,654評論 2 354

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