前言
今天給大家介紹下Highlight。
Highlight相關屬性
/**
* the x-value of the highlighted value
*/
private float mX = Float.NaN;
/**
* the y-value of the highlighted value
*/
private float mY = Float.NaN;
/**
* the x-pixel of the highlight
*/
private float mXPx;
/**
* the y-pixel of the highlight
*/
private float mYPx;
/**
* the index of the data object - in case it refers to more than one
*/
private int mDataIndex = -1;
/**
* the index of the dataset the highlighted value is in
*/
private int mDataSetIndex;
/**
* index which value of a stacked bar entry is highlighted, default -1
*/
private int mStackIndex = -1;
/**
* the axis the highlighted value belongs to
*/
private YAxis.AxisDependency axis;
/**
* the x-position (pixels) on which this highlight object was last drawn
*/
private float mDrawX;
/**
* the y-position (pixels) on which this highlight object was last drawn
*/
private float mDrawY;
光看一堆代碼,沒意思哈。直接上圖:
上圖是 MPAndroidChart Example 中的LinechartActivity1的截圖。我們可以看到,有一個十字交叉線,十字交叉的地方就是圖中的數據點,說明已經Highlight選中了這個點。
我們來看下這張圖對應的Highlight的屬性的值是多少:
mX = 7,mY = 67.5
mXPx = mX 對應的屏幕座標的px值 mYPx = mY 對應的屏幕座標的px值
mDataSetIndex = 0 (只有一條線)
axis = AxisDependency.LEFT
mDrawX = mXPx (最後一次的畫過的X座標)
mDrawY = mYPx (最後一次的畫過的Y座標)
下面是我的小項目中的的一個截圖,找找有什麼不一樣啊?
不同點一:十字線的交叉點是鼠標或者說是手指觸摸的點。
剛開始做的時候,沒注意到這點,因爲有兩條線,一個是分時線(藍色),一個是均線(黃色),如果選中了某一個點,那麼會有兩條橫着的Highlight線,這樣就不美觀了。再仔細對照了下設計圖,十字交叉的地方是手指觸摸的地方。那有啥辦法,硬着頭皮改源碼。首先弄清Highlight每個屬性的含義,然後找到對應的畫Highlight線的地方,改下就好了。這個還是蠻簡單的。
不同點二:有多條折線,折線與豎直的線重合的點會有個小圓點標記。
這些個小圓點也是要自己動手在原來基礎上添加。
不同點三:有MarkerView,也就是我之後要和大家介紹的。
不同點四:有兩個Y軸,橫軸是時間軸,不是從0開始。
剛開始我曾想過,時間作爲橫軸的話,在new Entry(x,y)的時候x傳時間,y傳值。可仔細一看,x是Int類型,沒有重載的String類型。那怎麼辦?看了他內部實現才知道,數據創建了之後,整個Chart的移動,拖拽,放大,等操作,都是通過Matrix實現的。Matrix總不可能拿着一個時間去操作吧。後面一想,只要數據點和對應的時間對應上就好了。比如9點30分對應第一個數據點。這樣就能一一找到每個點對應的時間值了。
畫HightLight線
假設我們是在做出長按事件後,畫出高亮線的。如何實現呢?來看看源碼吧。
首先找突破點,長按事件與事件監聽有關,我們找到了BarLineChartTouchListener類。發現裏面有個重載方法:
@Override
public void onLongPress(MotionEvent e) {
mLastGesture = ChartGesture.LONG_PRESS;
OnChartGestureListener l = mChart.getOnChartGestureListener();
if (l != null) {
l.onChartLongPressed(e);
}
Highlight h = mChart.getHighlightByTouchPoint(e.getX(), e.getY());
performHighlight(h, e);
mChart.disableScroll();
}
這就是長按事件的監聽,長按事件觸發後,獲取手指觸摸的地方對應的Highlight,然後調用performHighlight(h, e)方法:
protected void performHighlight(Highlight h, MotionEvent e) {
if (h == null || h.equalTo(mLastHighlighted)) {
mChart.highlightValue(null, true);
mLastHighlighted = null;
} else {
mChart.highlightValue(h, true);
mLastHighlighted = h;
}
}
從中,我們看到了,方法中調用了highlightValue(h, true)方法,繼續跟蹤:
/**
* Highlights the value selected by touch gesture. Unlike
* highlightValues(...), this generates a callback to the
* OnChartValueSelectedListener.
* @param high - the highlight object
* @param callListener - call the listener
*/
public void highlightValue(Highlight high, boolean callListener) {
Entry e = null;
if (high == null)
mIndicesToHighlight = null;
else {
if (mLogEnabled)
Log.i(LOG_TAG, "Highlighted: " + high.toString());
long start = System.currentTimeMillis();
e = mData.getEntryForHighlight(high);
long stop = System.currentTimeMillis();
if (mLogEnabled)
Log.i(LOG_TAG, "Highlighted: " + (stop-start)+"ms");
if (e == null) {
mIndicesToHighlight = null;
high = null;
} else {
// set the indices to highlight
mIndicesToHighlight = new Highlight[]{
high
};
}
}
setLastHighlighted(mIndicesToHighlight);
if (callListener && mSelectionListener != null) {
if (!valuesToHighlight())
mSelectionListener.onNothingSelected();
else {
// notify the listener
mSelectionListener.onValueSelected(e, high);
}
}
// redraw the chart
invalidate();
}
前面一大段代碼,就是檢查這個Highlight有沒有對應的Entry。如果沒有,那就置Highlight = null.如果有,那就new 一個 Highlight數組。下面一段代碼呢就是畫出這個Highlight之後的一個觸發監聽,可以其中做些操作,不要太耗時。最重要的是有個方法,我們之前見過:
/**
* Returns true if there are values to highlight, false if there are no
* values to highlight. Checks if the highlight array is null, has a length
* of zero or if the first object is null.
* @return
*/
public boolean valuesToHighlight() {
return mIndicesToHighlight == null || mIndicesToHighlight.length <= 0
|| mIndicesToHighlight[0] == null ? false
: true;
}
在OnDraw方法中見到過,對吧,再回憶下:
if (valuesToHighlight())
mRenderer.drawHighlighted(canvas, mIndicesToHighlight);
滿足這幾個條件。纔給你繪製Highlight。