轉載於:
Android觸控屏幕Gesture(GestureDetector和SimpleOnGestureListener的使用教程)
1、當用戶觸摸屏幕的時候,會產生許多手勢,例如down,up,scroll,filing等等,我們知道View類有個View.OnTouchListener內部接口,通過重寫他的onTouch(View v, MotionEvent event)方法,我們可以處理一些touch事件,但是這個方法太過簡單,如果需要處理一些複雜的手勢,用這個接口就會很麻煩(因爲我們要自己根據用戶觸摸的軌跡去判斷是什麼手勢)Android sdk給我們提供了GestureDetector(Gesture:手勢Detector:識別)類,通過這個類我們可以識別很多的手勢,主要是通過他的onTouchEvent(event)方法完成了不同手勢的識別。雖然他能識別手勢,但是不同的手勢要怎麼處理,應該是提供給程序員實現的,因此這個類對外提供了兩個接口:OnGestureListener,OnDoubleTapListener,還有一個內部類SimpleOnGestureListener,SimpleOnGestureListener類是GestureDetector提供給我們的一個更方便的響應不同手勢的類,這個類實現了上述兩個接口(但是所有的方法體都是空的),該類是static class,也就是說它實際上是一個外部類。程序員可以在外部繼承這個類,重寫裏面的手勢處理方法。
通過GestureDetector的構造方法可以將SimpleOnGestureListener對象傳遞進去,這樣GestureDetector能處理不同的手勢了。
2.、具體用法:
/**
* 當我們捕捉到Touch操作的時候,如何識別出用戶的Gesture?這裏我們需要GestureDetector.OnGestureListener接口的幫助
*
* @author HB
*/
public class MySurfaceView extends SurfaceView implements OnGestureListener,
OnTouchListener, Callback {
GestureDetector gd;
Context context;
public MySurfaceView(Context context) {
super(context);
this.context = context;
setFocusable(true);
requestFocus();
this.setLongClickable(true);
this.setOnTouchListener(this);
setFocusable(true);
gd = new GestureDetector(new MySimpleGesture());// 這裏或者可以直接傳遞this參數,因爲本類已經繼承了OnGestureListener接口,也可以把new
// MySimpleGesture(),它繼承了SimpleOnGestureListener類;,兩種方法都可以,只是把兩種方法歸在一個裏面,方便學習;
// 。實惠屏幕觸控事件;
gd.setIsLongpressEnabled(true);
// TODO Auto-generated constructor stub
}
// 用戶輕觸觸摸屏,由1個MotionEvent ACTION_DOWN觸發
@Override
public boolean onDown(MotionEvent e) {
// TODO Auto-generated method stub
System.out.println("onDown");
return false;
}
/*
* 用戶輕觸觸摸屏,尚未鬆開或拖動,由一個1個MotionEvent ACTION_DOWN觸發
* 注意和onDown()的區別,強調的是沒有鬆開或者拖動的狀態 (單擊沒有鬆開或者移動時候就觸發此事件,再觸發onLongPress事件)
*/
@Override
public void onShowPress(MotionEvent e) {
// TODO Auto-generated method stub
System.out.println("onShowPress");
}
// 用戶(輕觸觸摸屏後)鬆開,由一個1個MotionEvent ACTION_UP觸發
@Override
public boolean onSingleTapUp(MotionEvent e) {
// TODO Auto-generated method stub
System.out.println("onSingleTopUp");
return false;
}
// 用戶按下觸摸屏,並拖動,由1個MotionEvent ACTION_DOWN, 多個ACTION_MOVE觸發
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) {
System.out.println("onScroll");
// TODO Auto-generated method stub
return false;
}
// 用戶長按觸摸屏,由多個MotionEvent ACTION_DOWN觸發
@Override
public void onLongPress(MotionEvent e) {
// TODO Auto-generated method stub
System.out.println("onLongPress");
}
/*
* 用戶按下觸摸屏、快速移動後鬆開,由1個MotionEvent ACTION_DOWN, 多個ACTION_MOVE,
* 1個ACTION_UP觸發(non-Javadoc)
* Fling事件的處理代碼:除了第一個觸發Fling的ACTION_DOWN和最後一個ACTION_MOVE中包含的座標等信息外
* ,我們還可以根據用戶在X軸或者Y軸上的移動速度作爲條件
* 比如下面的代碼中我們就在用戶移動超過100個像素,且X軸上每秒的移動速度大於200像素時才進行處理。
*
* @see android.view.GestureDetector.OnGestureListener#onFling(android.view.
* MotionEvent, android.view.MotionEvent, float, float)
* 這個例子中,tv.setLongClickable( true )是必須的,因爲
* 只有這樣,view才能夠處理不同於Tap(輕觸)的hold(即ACTION_MOVE,或者多個ACTION_DOWN)
* ,我們同樣可以通過layout定義中的android:longClickable來做到這一點
*/
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
// TODO Auto-generated method stub
System.out.println("onFling");
// 參數解釋:
// e1:第1個ACTION_DOWN MotionEvent
// e2:最後一個ACTION_MOVE MotionEvent
// velocityX:X軸上的移動速度,像素/秒
// velocityY:Y軸上的移動速度,像素/秒
// 觸發條件 :
// X軸的座標位移大於FLING_MIN_DISTANCE,且移動速度大於FLING_MIN_VELOCITY個像素/秒
final int FLING_MIN_DISTANCE = 100, FLING_MIN_VELOCITY = 200;
if (e1.getX() - e2.getX() > FLING_MIN_DISTANCE
&& Math.abs(velocityX) > FLING_MIN_VELOCITY) {
// Fling left
Log.i("MyGesture", "Fling left");
Toast.makeText(context, "Fling Left", Toast.LENGTH_SHORT).show();
} else if (e2.getX() - e1.getX() > FLING_MIN_DISTANCE
&& Math.abs(velocityX) > FLING_MIN_VELOCITY) {
// Fling right
Log.i("MyGesture", "Fling right");
Toast.makeText(context, "Fling Right", Toast.LENGTH_SHORT).show();
}
return true;
}
/**
* 當發行屏幕觸控事件的時候,首先出發此方法,再通過此方法,監聽具體的整件
* 在onTouch()方法中,我們調用GestureDetector的onTouchEvent
* ()方法,將捕捉到的MotionEvent交給GestureDetector 來分析是否有合適的callback函數來處理用戶的手勢
*/
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
System.out.println("onTouch");
return gd.onTouchEvent(event);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
/**
* SimpleOnGestureListener implements GestureDetector.OnDoubleTapListener,
* GestureDetector.OnGestureListener
*/
private class MySimpleGesture extends SimpleOnGestureListener {
// 雙擊的第二下Touch down時觸發
public boolean onDoubleTap(MotionEvent e) {
Log.i("MyGesture", "onDoubleTap");
return super.onDoubleTap(e);
}
// 雙擊的第二下Touch down和up都會觸發,可用e.getAction()區分
public boolean onDoubleTapEvent(MotionEvent e) {
Log.i("MyGesture", "onDoubleTapEvent");
return super.onDoubleTapEvent(e);
}
// Touch down時觸發
public boolean onDown(MotionEvent e) {
Log.i("MyGesture", "onDown");
return super.onDown(e);
}
// Touch了滑動一點距離後,up時觸發
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
Log.i("MyGesture", "onFling");
return super.onFling(e1, e2, velocityX, velocityY);
}
// Touch了不移動一直Touch down時觸發
public void onLongPress(MotionEvent e) {
Log.i("MyGesture", "onLongPress");
super.onLongPress(e);
}
// Touch了滑動時觸發
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
Log.i("MyGesture", "onScroll");
return super.onScroll(e1, e2, distanceX, distanceY);
}
/*
* Touch了還沒有滑動時觸發 (1)onDown只要Touch Down一定立刻觸發 (2)Touch
* Down後過一會沒有滑動先觸發onShowPress再觸發onLongPress So: Touch Down後一直不滑動,onDown
* -> onShowPress -> onLongPress這個順序觸發。
*/
public void onShowPress(MotionEvent e) {
Log.i("MyGesture", "onShowPress");
super.onShowPress(e);
}
/*
* 兩個函數都是在Touch Down後又沒有滑動(onScroll),又沒有長按(onLongPress),然後Touch Up時觸發
* 點擊一下非常快的(不滑動)Touch Up: onDown->onSingleTapUp->onSingleTapConfirmed
* 點擊一下稍微慢點的(不滑動)Touch Up://確認是單擊事件觸發
* onDown->onShowPress->onSingleTapUp->onSingleTapConfirmed
*/
public boolean onSingleTapConfirmed(MotionEvent e) {
Log.i("MyGesture", "onSingleTapConfirmed");
return super.onSingleTapConfirmed(e);
}
public boolean onSingleTapUp(MotionEvent e) {
Log.i("MyGesture", "onSingleTapUp");
return super.onSingleTapUp(e);
}
}
}
結果:
1、當單擊屏幕的時候,輸出:
2、當單擊等一會再鬆開時候輸出(觸觸摸屏,比單擊慢):
3、當用戶按住不放的時候,輸出:
4、當用戶按住不放,拖動鼠標的時候輸出:
5、當用戶按住不放,快速拖動鼠標的時候:
6、當用戶雙擊的時候(觀察與單擊的區別---onDubleTab在第二次按下Down的時候纔出發,說明 是雙擊事件在onDown事件之前;):