今天来详细说一下android中常常使用的GestureDetector。先来看看google对GestureDetector的介绍:
/** * Detects various gestures and events using the supplied {@link MotionEvent}s. * The {@link OnGestureListener} callback will notify users when a particular * motion event has occurred. This class should only be used with {@link MotionEvent}s * reported via touch (don‘t use for trackball events). * * To use this class: * <ul> * <li>Create an instance of the {@code GestureDetector} for your {@link View} * <li>In the {@link View#onTouchEvent(MotionEvent)} method ensure you call * {@link #onTouchEvent(MotionEvent)}. The methods defined in your callback * will be executed when the events occur. * </ul> */上面主要说了GestureDetector的作用和使用方法,这里我先做一下大意的翻译:GestureDetector可以通过view的onTouchEvent带回的MotionEvent来判断出特殊的手势,当检测到有特殊的手势发生时,就会回调对应的特殊方法来告知用户。
从上述可以知道,对于GestureDetector的使用主要有两个地方需要我们自己来做:
(1)在需要检测手势的view或者activity等 ,需要在其onTouchEvent(MotionEvent event)方法里面实时将event信息传递给你的GestureDetector对象,比如下来这样:
@Override public boolean onTouchEvent(MotionEvent event) { // TODO Auto-generated method stub return this.detector.onTouchEvent(event); }(2)上面说,当有特殊的手势时候会调用特殊的回调方法,所以这里还需要我们去写对于特殊手势的回调函数。GestureDetector里面定义了不同的接口函数来对应不同的手势。所以我们只需要实现GestureDetector里面的手势接口方法即可。
GestureDetector的手势接口分两种:OnGestureListener主要处理单点触摸、OnDoubleTapListener主要是处理两点触摸。一般情况,你希望用到那一种就实现一种的接口就可以了。然后把实现手势接口的对象传递给你的GestureDetector就可以了。
在GestureDetector.java有其对GestureDetector的定义,从中可以看到定义的一个变量 private final OnGestureListener mListener; 其中mListener就是指向我们自己实现手势接口的对象。我们来看看GestureDetector的一个最终的构造函数:
public GestureDetector(Context context, OnGestureListener listener, Handler handler) { if (handler != null) { mHandler = new GestureHandler(handler); } else { mHandler = new GestureHandler(); } mListener = listener; if (listener instanceof OnDoubleTapListener) { setOnDoubleTapListener((OnDoubleTapListener) listener); } init(context); }
public class LightActivity extends Activity implements OnTouchListener, OnGestureListener { private static String MY_PKG_NAME = "com.android.camera"; private LinearLayout mlayout; private GestureDetector detector; // 申明一个GestureDetector ... ... @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_light); CloseCamera(); mlayout = (LinearLayout) findViewById(R.id.mlayou); detector = new GestureDetector(this); // 实例化一个对象,这里传递的是LightActivity对象,因为LightActivity实现了OnGestureListener 接口 Resources resources = this.getResources(); ... ... } ... ... @Override public boolean onTouchEvent(MotionEvent event) { // TODO Auto-generated method stub return this.detector.onTouchEvent(event); // 这里实时将MotionEvent 传递给我们的detector } ... ...
// 下面你的几个方法是实现接口OnGestureListener
@Override
public boolean onDown(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
// TODO Auto-generated method stub
// ????????????
/*
* if (e1.getX() - e2.getX() > FLING_MIN_DISTANCE && Math.abs(velocityX)
* > FLING_MIN_VELOCITY) { if (IsOpenFlash) { // Fling left
* mVibrator.vibrate(off, -1); closeFlashLight();
* mlayout.setBackgroundDrawable(mdrawable_off); } } else if (e2.getX()
* - e1.getX() > FLING_MIN_DISTANCE && Math.abs(velocityX) >
* FLING_MIN_VELOCITY) { if (!IsOpenFlash) { // Fling right
* mVibrator.vibrate(on, -1); openFlashLight();
* mlayout.setBackgroundDrawable(mdrawable_on); } }
*/
return false;
}
@Override
public void onLongPress(MotionEvent e) {
// TODO Auto-generated method stub
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
// TODO Auto-generated method stub
// 锟斤拷锟斤拷
if ((e1.getY() > MAX_UP && e2.getY() < MAX_DOWN)
&& (e1.getX() > MAX_LEFT && e2.getX() < MAX_RIGHT)) {
if (e1.getY() - e2.getY() > FLING_MIN_DISTANCE
&& Math.abs(distanceY) > FLING_MIN_VELOCITY) {
if (!IsOpenFlash) {
// Fling up
mVibrator.vibrate(on, -1);
openFlashLight();
mlayout.setBackgroundDrawable(mdrawable_on);
}
} else if (e2.getY() - e1.getY() > FLING_MIN_DISTANCE
&& Math.abs(distanceY) > FLING_MIN_VELOCITY) {
if (IsOpenFlash) {
// Fling down
mVibrator.vibrate(off, -1);
closeFlashLight();
mlayout.setBackgroundDrawable(mdrawable_off);
}
}
}
return false;
}
@Override
public void onShowPress(MotionEvent e) {
// TODO Auto-generated method stub
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
...
...
}
最后我们来介绍一下GestureDetector的手势接口方法:
(1)OnGestureListener
boolean onDown(MotionEvent e); // 点击时候一触摸到屏就会发生
void onShowPress(MotionEvent e); // 在点击触摸到屏时候、并且move or up都还没有发生时候 就会发生。其实就是在onDown之后,原则上第一个会发生的手势。
boolean onSingleTapUp(MotionEvent e); // 当单个点击触摸屏UP(离开)的时候发生的手势,这里为什么是SingleTap呢? 就是要区别多点触摸,所以这里其实是指只有一个手指触摸屏时候,up(离开屏)的时候发生的手势。
void onLongPress(MotionEvent e);// 长按手势
boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);// 是指触摸屏的时候,在屏上面滑动的时候发生的手势,其实上是在MotionEvent.ACTION_MOVE的时候才会发生的手势。
boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY); // 这个和onScroll不一样,这个主要是用于识别用户在move的时候,突然UP的时候才会发生的手势。velocityX 和velocityY是指速率(这里是一个second移动的距离);MotionEvent e1当前这个手势发生的down motion event ;MotionEvent e2 发生这个手势的move motion event。onFling主要用于判断用户的意图,
对于onFling和onScroll我们来举例说明: onScroll一般用于识别用户对图片的放大、缩小意图;onFling常用于识别用户看电子 书的时候翻页的意图。
(2)OnDoubleTapListener:
boolean onSingleTapConfirmed(MotionEvent e); // 确认只是一次点击的时候发生的手势,这里其实是第一次点击后,一段时间内没有再收到一个一个点击,则发生该手势。这里的一段时间其实就是一点确认是否是双击的时间:ViewConfiguration.getDoubleTapTimeout()。在ViewConfiguration.java里面有其定义时间长度:
/** * Defines the duration in milliseconds between the first tap‘s up event and * the second tap‘s down event for an interaction to be considered a * double-tap. */ private static final int DOUBLE_TAP_TIMEOUT = 300;
boolean onDoubleTap(MotionEvent e);// 双击的时候发生的手势。参数:MotionEvent e 是指第一次点击的事件。
boolean onDoubleTapEvent(MotionEvent e);// // 双击发生的过程中发生的手势。
其实GestureDetector的处理核心代码是public boolean onTouchEvent(MotionEvent ev),这个方法做了所有对手势的检测和区分。如还是不太理解各个手势是如何发生的话可以去看看这个方法。