Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android判斷雙擊事件(參考android源碼,判斷時間間隔和范圍)

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

編輯:關於Android編程

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

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

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

需要特殊說明的是OnDoubleTapListener這個接口,GestureDetector有個函數setOnDoubleTapListener來設置OnDoubleTapListener,而不是通過構造函數的方式,但讓了通過構造函數的方式也不是不可以,大家可以參考下面的博客:

/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

....
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);
....

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

2.mPriviousUpEvent

....
case MotionEvent.ACTION_UP:
            mStillDown = false;
            MotionEvent currentUpEvent = MotionEvent.obtain(ev);
            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);
                }
            }
            if (mPreviousUpEvent != null) {
                mPreviousUpEvent.recycle();
            }
            // Hold the event we obtained above - listeners may have changed the original.
            mPreviousUpEvent = currentUpEvent;
....

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

3.ev

....
public boolean onTouchEvent(MotionEvent ev) {
        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;

然後獲取三個參數:

@Override
	public 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,這樣就大功告成了,是不是比以前用的好多了呢?~!.~




  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved