在Android系統中,每一次手勢交互都會依照以下順序執行。
1. 接觸接觸屏一剎那,觸發一個MotionEvent事件。
2. 該事件被OnTouchListener監聽,在其onTouch()方法裏獲得該MotionEvent對象。
3. 通過GestureDetector(手勢識別器)轉發次MotionEvent對象
MotionEvent: 這個類用於封裝手勢、觸摸筆、軌跡球等等的動作事件。其內部封裝了兩個重要的屬性X和Y,這兩個屬性分別用於記錄橫軸和縱軸的座標。
GestureDetector: 識別各種手勢,它提供了OnGestureListener和OnDoubleTapListener兩個接口,以及一個內部類SimpleOnGestureListener。
手勢交互的監聽接口,其中提供了多個抽象方法,並根據GestureDetector的手勢識別結果調用相對應的方法。
代碼說明:
佈局:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="@+id/iv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/a" />
</RelativeLayout>
實現OnGestureListener接口:
package com.example.gesturedetectortest;
import android.os.Bundle;
import android.util.Log;
import android.app.Activity;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;
// OnGestureListener: 這是一個手勢交互的監聽接口,
//其中提供了多個抽象方法,並根據GestureDetector的手勢識別結果調用相對應的方法。
public class MainActivity extends Activity implements OnGestureListener,OnTouchListener{
public static final String TAG=MainActivity.class.getSimpleName();
private ImageView iv;
private GestureDetector detector;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iv=(ImageView)findViewById(R.id.iv);
detector=new GestureDetector(this, this);
iv.setOnTouchListener(this);
}
//在onTouchEvent()方法中,我們調用GestureDetector的onTouchEvent()方法,
//將捕捉到的MotionEvent交給GestureDetector來分析是否有合適的callback函數來處理用戶的手勢
// @Override
// public boolean onTouchEvent(MotionEvent event) {
// // TODO Auto-generated method stub
// return this.detector.onTouchEvent(event);
// }
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
return this.detector.onTouchEvent(event);
}
//剛剛手指接觸到觸摸屏的那一剎那,由1個MotionEvent ACTION_DOWN觸發
@Override
public boolean onDown(MotionEvent e) {
// TODO Auto-generated method stub
Log.i(TAG, "onDown y=" + e.getY());
return true;
}
// 手指按在觸摸屏上,它的時間範圍在按下起效,在長按之前,
//由一個1個MotionEvent ACTION_DOWN觸發
//注意和onDown()的區別,強調的是沒有鬆開或者拖動的狀態
@Override
public void onShowPress(MotionEvent e) {
// TODO Auto-generated method stub
Log.i(TAG, "onShowPress");
}
//手指離開觸摸屏的那一剎那
//由一個1個MotionEvent ACTION_UP觸發
@Override
public boolean onSingleTapUp(MotionEvent e) {
// TODO Auto-generated method stub
Log.i(TAG, "onSingleTapUp y=" + e.getY());
return true;
}
//手指按下且在屏上滑動
//由1個MotionEvent ACTION_DOWN, 多個ACTION_MOVE觸發
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
// TODO Auto-generated method stub
Log.i(TAG, "onScroll:distanceX = " + distanceX + " distanceY = " + distanceY);
return true;
}
//手指長按觸屏幕,並且沒有鬆開
//由多個MotionEvent ACTION_DOWN觸發
@Override
public void onLongPress(MotionEvent e) {
// TODO Auto-generated method stub
Log.i(TAG, "onLongPress");
}
//手指在觸摸屏上迅速移動,並鬆開的動作
//由1個MotionEvent ACTION_DOWN, 多個ACTION_MOVE, 1個ACTION_UP觸發
//e1:第1個ACTION_DOWN MotionEvent ,e2:最後一個ACTION_MOVE MotionEven
//velocityX:X軸上的移動速度,像素/秒 ,velocityY:Y軸上的移動速度,像素/秒
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
// TODO Auto-generated method stub
Log.i(TAG, "onFling");
if(e1.getX()-e2.getX()>100&&Math.abs(velocityX)>200){
Log.i(TAG, "onFling 向左滑動");
return true;
}else if(e1.getX()-e2.getX()<-100&&Math.abs(velocityX)>200){
Log.i(TAG, "onFling 向右滑動");
return true;
}else if(e1.getY()-e2.getY()>10&&Math.abs(velocityY)>50){
Log.i(TAG, "onFling 向上滑動 上位移="+(e1.getY()-e2.getY()));
return true;
}else if(e1.getY()-e2.getY()<-10&&Math.abs(velocityY)>50){
Log.i(TAG, "onFling 向下滑動 下位移"+(e1.getY()-e2.getY()));
return true;
}
return false;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
onFling方法中可以通過其參數進行一些條件設置,如左右上下滑動的條件。
Activity中的onTouchEvent方法和OnTouchListener中的onTouch方法,都可以實現調用GestureDetector的onTouchEvent()方法,將捕捉到的MotionEvent交給GestureDetector來分析是否有合適的callback函數來處理用戶的手勢,兩個直接的區別:查看http://www.xuebuyuan.com/1588148.html。
執行不同手勢時,logcat顯示:
下面這個測試,來自網絡,其實和OnGestureListener比較多了幾個方法。
package com.example.gesturedetectortest;
import android.app.Activity;
import android.os.Bundle;
import android.os.storage.OnObbStateChangeListener;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.OnDoubleTapListener;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;
public class SimpleOnGestureActivity extends Activity implements OnTouchListener{
public static final String TAG=SimpleOnGestureActivity.class.getSimpleName();
private GestureDetector detector;
private ImageView iv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gestrue);
iv=(ImageView)findViewById(R.id.iv);
detector=new GestureDetector(this, new MySimpleGesture());
iv.setOnTouchListener(this);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
return this.detector.onTouchEvent(event);
}
private class MySimpleGesture extends SimpleOnGestureListener{
// 雙擊的第二下Touch down時觸發
public boolean onDoubleTap(MotionEvent e) {
Log.i(TAG, "onDoubleTap");
return super.onDoubleTap(e);
}
// 雙擊的第二下Touch down和up都會觸發,可用e.getAction()區分
public boolean onDoubleTapEvent(MotionEvent e) {
Log.i(TAG, "onDoubleTapEvent");
return super.onDoubleTapEvent(e);
}
// Touch down時觸發
public boolean onDown(MotionEvent e) {
Log.i(TAG, "onDown");
return super.onDown(e);
}
// Touch了滑動一點距離後,up時觸發
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
Log.i(TAG, "onFling");
return super.onFling(e1, e2, velocityX, velocityY);
}
// Touch了不移動一直Touch down時觸發
public void onLongPress(MotionEvent e) {
Log.i(TAG, "onLongPress");
super.onLongPress(e);
}
// Touch了滑動時觸發
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
Log.i(TAG, "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(TAG, "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(TAG, "onSingleTapConfirmed");
return super.onSingleTapConfirmed(e);
}
public boolean onSingleTapUp(MotionEvent e) {
Log.i(TAG, "onSingleTapUp");
return super.onSingleTapUp(e);
}
}
}
一些關於手勢的優秀的開源框架:http://jcodecraeer.com/plus/list.php?tid=31&codecategory=16500