HighLight

前言

今天給大家介紹下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。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章