android判斷雙擊事件(參考android源碼,判斷時間間隔和範圍)

來源:互聯網
上載者:User

標籤:android   監聽雙擊事件   源碼解讀   

對於android的雙擊事件的判斷,官方是已經給出解決辦法的,主要是使用下面幾個類或者介面:GestureDetector,OnGestureListener,OnDoubleTapListener,GestureDetector.SimpleOnGestureListener

對於它們的介紹以及用法很多了,就不說明了,大家可以參考下面的部落格:

http://blog.sina.com.cn/s/blog_77c6324101017hs8.html

需要特殊說明的是OnDoubleTapListener這個介面,GestureDetector有個函數setOnDoubleTapListener來設定OnDoubleTapListener,而不是通過建構函式的方式,但讓了通過建構函式的方式也不是不可以,大家可以參考下面的部落格:

http://www.2cto.com/kf/201211/165457.html

通過上面的學習,相信大家就會對這個幾個類用的很熟練了,但是這個並不是我們這篇部落格的重點。

如果你因為某些原因,或者說,就是不想用上面的方法,非要用MotionEvent來判斷雙擊的時間的話,那也木有辦法!~這個網上也有很多的部落格進行了說明。

但是它們的部落格無論什麼實現,都只是通過時間進行判斷,並且也不會進行範圍的判斷,試想,如果你很快速的點擊螢幕最上面和最下面的兩個點,如果按照網路上大部分判斷時間的做法,那肯定就是雙擊時間,但是這顯然是不合理的。

那麼官方源碼是怎麼判斷的呢?我們一起先來看看,博主參考的是android-17版本的源碼。

.... case MotionEvent.ACTION_DOWN:            if (mDoubleTapListener != null) {                boolean hadTapMessage = mHandler.hasMessages(TAP);                if (hadTapMessage) mHandler.removeMessages(TAP);                if ((mCurrentDownEvent != null) && (mPreviousUpEvent != null) && hadTapMessage &&                        isConsideredDoubleTap(mCurrentDownEvent, mPreviousUpEvent, ev)) {                    // This is a second tap                    mIsDoubleTapping = true;                    // Give a callback with the first tap of the double-tap                    handled |= mDoubleTapListener.onDoubleTap(mCurrentDownEvent);                    // Give a callback with down event of the double-tap                    handled |= mDoubleTapListener.onDoubleTapEvent(ev);                } else {                    // This is a first tap                    mHandler.sendEmptyMessageDelayed(TAP, DOUBLE_TAP_TIMEOUT);                }            }            mDownFocusX = mLastFocusX = focusX;            mDownFocusY = mLastFocusY = focusY;            if (mCurrentDownEvent != null) {                mCurrentDownEvent.recycle();            }            mCurrentDownEvent = MotionEvent.obtain(ev);            mAlwaysInTapRegion = true;            mAlwaysInBiggerTapRegion = true;            mStillDown = true;            mInLongPress = false;            mDeferConfirmSingleTap = false;....
很明顯的看出來,它們是通過下面這個方法來判斷是否需要分發雙擊事件的:
isConsideredDoubleTap(mCurrentDownEvent, mPreviousUpEvent, ev)
下面的代碼就是調用listener的介面來處理雙擊事件,並且擷取處理結果,接著後面就是事件分發機制的事情了,不再本文討論範圍之內。
handled |= mDoubleTapListener.onDoubleTap(mCurrentDownEvent);
那麼,那三個參數是怎麼來的呢?我們一個一個來看。

1.mCurrentDownEvent

<span style="color:#333333;">....case MotionEvent.ACTION_DOWN:            if (mDoubleTapListener != null) {                boolean hadTapMessage = mHandler.hasMessages(TAP);                if (hadTapMessage) mHandler.removeMessages(TAP);                if ((mCurrentDownEvent != null) && (mPreviousUpEvent != null) && hadTapMessage &&                        isConsideredDoubleTap(mCurrentDownEvent, mPreviousUpEvent, ev)) {                    // This is a second tap                    mIsDoubleTapping = true;                    // Give a callback with the first tap of the double-tap                    handled |= mDoubleTapListener.onDoubleTap(mCurrentDownEvent);                    // Give a callback with down event of the double-tap                    handled |= mDoubleTapListener.onDoubleTapEvent(ev);                } else {                    // This is a first tap                    mHandler.sendEmptyMessageDelayed(TAP, DOUBLE_TAP_TIMEOUT);                }            }            mDownFocusX = mLastFocusX = focusX;            mDownFocusY = mLastFocusY = focusY;            </span><span style="color:#ff6666;">if (mCurrentDownEvent != null) {                mCurrentDownEvent.recycle();            }            mCurrentDownEvent = MotionEvent.obtain(ev);</span><span style="color:#333333;">....</span>

紅色的字型表明了,是上一次觸發DOWN事件的MotionEvent。

2.mPriviousUpEvent

....case MotionEvent.ACTION_UP:            mStillDown = false;            <span style="color:#ff6666;">MotionEvent currentUpEvent = MotionEvent.obtain(ev);</span>            if (mIsDoubleTapping) {                // Finally, give the up event of the double-tap                handled |= mDoubleTapListener.onDoubleTapEvent(ev);            } else if (mInLongPress) {                mHandler.removeMessages(TAP);                mInLongPress = false;            } else if (mAlwaysInTapRegion) {                handled = mListener.onSingleTapUp(ev);                if (mDeferConfirmSingleTap && mDoubleTapListener != null) {                    mDoubleTapListener.onSingleTapConfirmed(ev);                }            } else {                // A fling must travel the minimum tap distance                final VelocityTracker velocityTracker = mVelocityTracker;                final int pointerId = ev.getPointerId(0);                velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity);                final float velocityY = velocityTracker.getYVelocity(pointerId);                final float velocityX = velocityTracker.getXVelocity(pointerId);                if ((Math.abs(velocityY) > mMinimumFlingVelocity)                        || (Math.abs(velocityX) > mMinimumFlingVelocity)){                    handled = mListener.onFling(mCurrentDownEvent, ev, velocityX, velocityY);                }            }            <span style="color:#ff6666;">if (mPreviousUpEvent != null) {                mPreviousUpEvent.recycle();            }</span>            // Hold the event we obtained above - listeners may have changed the original.            <span style="color:#ff6666;">mPreviousUpEvent = currentUpEvent;</span>....

可以看出來,是上一次觸發UP事件的MotionEvent。

3.ev

....public boolean onTouchEvent(MotionEvent <span style="color:#ff6666;">ev</span>) {        if (mInputEventConsistencyVerifier != null) {            mInputEventConsistencyVerifier.onTouchEvent(ev, 0);        }        final int action = ev.getAction();....
就是當前發生的MotionEvent的事件。

上述三個參數都找到了,接下來就是看看isConsideredDoubleTap方法裡面做了什麼。

private boolean isConsideredDoubleTap(MotionEvent firstDown, MotionEvent firstUp,            MotionEvent secondDown) {        if (!mAlwaysInBiggerTapRegion) {            return false;        }        if (secondDown.getEventTime() - firstUp.getEventTime() > DOUBLE_TAP_TIMEOUT) {            return false;        }        int deltaX = (int) firstDown.getX() - (int) secondDown.getX();        int deltaY = (int) firstDown.getY() - (int) secondDown.getY();        return (deltaX * deltaX + deltaY * deltaY < mDoubleTapSlopSquare);    }
方法很簡單,先判斷了事件,再判斷了範圍。下面看看相關參數的擷取,如下:

final ViewConfiguration configuration = ViewConfiguration.get(context);

private static final int DOUBLE_TAP_TIMEOUT = ViewConfiguration.getDoubleTapTimeout();

doubleTapSlop = configuration.getScaledDoubleTapSlop();

mDoubleTapSlopSquare = doubleTapSlop * doubleTapSlop;

經過上述的觀察,相信大家已經知道了,andorid自己是怎麼判斷的了吧?相應的,我們可以模仿來寫一寫。

首先初始化參數:

ViewConfiguration configuration = ViewConfiguration.get(this);

doubleTapSlop = configuration.getScaledDoubleTapSlop();mDoubleTapSlopSquare = doubleTapSlop * doubleTapSlop;

然後擷取三個參數:

@Overridepublic boolean onTouch(View v, MotionEvent event) {switch(event.getAction()){case MotionEvent.ACTION_DOWN:if(isConsideredDoubleTap(firstDown,firstUp,event)){hideOrShowTitleBar(menuRl.getVisibility() != View.GONE);}if (firstDown != null) {firstDown.recycle();            }firstDown = MotionEvent.obtain(event);hideOrShowTitleBar(menuRl.getVisibility() != View.GONE);break;case MotionEvent.ACTION_UP:if (firstDown != null) {firstUp.recycle();            }firstUp = MotionEvent.obtain(event);break;}return false;}

最後進行判斷:

/** * 一個方法用來判斷雙擊時間 * @param firstDown * @param firstUp * @param secondDown * @return */private boolean isConsideredDoubleTap(MotionEvent firstDowns,MotionEvent firstUps,MotionEvent secondDowns) {if(firstDowns == null || secondDowns == null){return false;}//System.out.println("secondDowns.getEventTime():"+secondDowns.getEventTime());//System.out.println("firstUps.getEventTime():"+firstUps.getEventTime());        if (secondDowns.getEventTime() - firstUps.getEventTime() > Constans.DOUBLE_TAP_TIMEOUT) {            return false;        }               int deltaX = (int) firstDowns.getX() - (int) secondDowns.getX();        int deltaY = (int) firstDowns.getY() - (int) secondDowns.getY();//        System.out.println("deltaX:"+deltaX);//        System.out.println("deltaY:"+deltaY);//        System.out.println("deltaX * deltaX + deltaY * deltaY:"+deltaY);//        System.out.println("mDoubleTapSlopSquare:"+mDoubleTapSlopSquare);        return (deltaX * deltaX + deltaY * deltaY < mDoubleTapSlopSquare);    }

ok,這樣就大功告成了,是不是比以前用的好多了呢?~!.~




android判斷雙擊事件(參考android源碼,判斷時間間隔和範圍)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.