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