在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