在使用自訂視圖的時候,對觸屏事件的處理是必不可少的,有能力的可以自己寫代碼處理,這樣更加的靈活。如果不想這麼麻煩,Android提供了一個手勢監聽類GestureDetector,可以供我們使用。GestureDetector使用很方便,提供了單擊,雙擊,長按等操作的處理,但是一般的定義介面都比較複雜,還用很多需要注意的地方,在這兒總結一下GestureDetector的使用。
首先建立一個空白的工程,主介面的layout中只需要添加一個按鈕就行
由於要測試的觸屏事件,所有這個按鈕比較大,主介面為如下效果:
首先介紹一下觸屏事件處理的基本思路。觸屏一般有三個基本事件,down按下,move移動,up離開,通過對這三個基本事件的監聽,判斷使用者執行了何種操作。一個標準的觸屏操作一般都是一系列基本事件的組合,在Android的架構中,通過onTouch()函數可以擷取基本的觸屏事件,而像onClick這樣的函數,已經是一系列基本事件的組合。
比如,發生了Down事件,在up事件之前沒有發生move事件,或者move的範圍很小,並且down事件和up事件的間隔很短,這就是一個click或者singelTap事件,
對比實體鍵盤按鍵的事件,實體鍵盤是在down事件發生後進行操作,而觸屏事件一般是up事件發生後進行操作。
下面是activity的代碼
MainActivity mGestureDetector = GestureDetector(, mButton = mButton.setOnTouchListener( Log.i(getClass().getName(), "onTouch-----" + String getActionName( String name = "" name = "ACTION_DOWN" name = "ACTION_MOVE" name = "ACTION_UP" MyOnGestureListener Log.i(getClass().getName(), "onSingleTapUp-----" + Log.i(getClass().getName(), "onLongPress-----" + onScroll(MotionEvent e1, MotionEvent e2, distanceX, "onScroll-----" + getActionName(e2.getAction()) + ",(" + e1.getX() + "," + e1.getY() + ") ,(" + e2.getX() + "," + e2.getY() + ")" onFling(MotionEvent e1, MotionEvent e2, velocityX, "onFling-----" + getActionName(e2.getAction()) + ",(" + e1.getX() + "," + e1.getY() + ") ,(" + e2.getX() + "," + e2.getY() + ")" Log.i(getClass().getName(), "onShowPress-----" + Log.i(getClass().getName(), "onDown-----" + Log.i(getClass().getName(), "onDoubleTap-----" + Log.i(getClass().getName(), "onDoubleTapEvent-----" + Log.i(getClass().getName(), "onSingleTapConfirmed-----" + }
首先是聲明一個GestureDetector,然後重寫Button的onTouch函數,將觸屏事件交給GestureDetector處理。
首先做一個對按鈕做一個單擊
onSingleTapUp被調用,說明發生了單擊事件,onSingleTapConfirmed被調用,說明確認發生了一個單擊事件,不是雙擊的事件。需要注意的是onSingleTapUp已經是一click事件,onSingleTapUp觸發的時候是ACTION_UP事件。onSingleTapConfirmed是在使用者手指離開螢幕後觸發,所有up並不是所有觸屏事件的結束。
做一個雙擊的操作
首先發生了一個onSingleTapUp,說明完成了一次單擊事件,然後發生了onDoubleTap,至此,一次雙擊事件已經完成。我們可以看到,onDoubleTap發生的時候是ACTION_DOWN事件,也就是說雙擊事件是第二次按下螢幕的時候觸發,而不是第二次離開螢幕的時候觸發,在onDoubleTap發生之後,就可以在onDoubleTapEvent中監聽到雙擊事件發生後從按下到彈起的所有觸屏事件。onDoubleTap發生後不會觸發onSingleTapUp和onSingleTapConfirmed。
做一個長按的操作
onLongPress實在ACTION_DOWN時發生,onLongPress發生後在up之前不會用其他事件觸發,可以在onShowPress處理狀態的改變,比如按鈕的按下狀態。
做一個滑動操作
onScroll事件是拖動,onFling是拋。結合log來瞭解一下。首先是ACTION_DOWN,之後多次ACTION_MOVE,移動超過一定距離,觸發了onScroll,如果onScroll被觸發,在up之前是不會有長按,單擊,雙擊等事件的。看一下onScroll的參數
onScroll(MotionEvent e1, MotionEvent e2, distanceX, distanceY)
e1為第一次按下的事件,和onDown事件裡面的一樣,e2為當前的事件,distanceX為本次onScroll移動的X軸距離,distanceY為移動的Y軸距離,移動的距離是相對於上一次onScroll事件的移動距離,而不是當前點和按下點的距離。
這次滑動最後觸發了onFling事件,但是onFling事件的觸發不是一定的,onFling是在ACTION_UP觸發,平時列表在離開螢幕是繼續滾動,就是通過這種方式觸發。
onFling(MotionEvent e1, MotionEvent e2, velocityX, velocityY)
onFling的前兩個參數和onScroll相同,e2為使用者拖動完離開螢幕時的點。veloctiyX,velocitY為離開螢幕時的初始速度,以這兩個速度為初始速度做勻減速運動,就是現在拖動列表和拖動圖片的各種緩衝滾動的效果。
函數的傳回值
除了onLongPress,這些函數都是有傳回值的,
mButton.setOnTouchListener( Log.i(getClass().getName(), "onTouch-----" + });
這些傳回值會通過 mGestureDetector.onTouchEvent(event); 傳遞給onTouch。
最後總結一下
GestureDetector結合SimpleOnGestureListener可以很方便的擷取到單擊,雙擊,長按等事件,但是對這些事件的處理不是簡單的在對應的函數裡做一些操作就可以的,複雜的自訂視圖還是要在onTouch裡面進行判斷個個控制項的焦點狀態,而且GestureDetector也不是萬能的,你如果要處理長按之後的移動,就要費一番功夫了,以為GestureDetector在長按發生後是不會在有onScroll的,你只能通過onTouch裡面的ACTION_MOVE處理。