当你把一个或者过个手指放在屏幕上的时候就会产生一个触摸手势,你的应用会会把你的触摸的模式翻译成一个特别的手势。下面手势检测中的两个相应的阶段:
1.搜集触摸事件的数据。
2.翻译这个数据,来查看是否符合app支持的某个手势的类别。
支持的库类
这个案例中使用的类是GestureDetectorCopat和MotionEventCompa类。这些类都是在支持库当中的。如果你要兼容android1.6以上的设备,你需要使用兼容包。要注意MotionEventComat不是MotionEvent的替代类。而是它提供了一要接受想要的和事件相关的动作,二讲MotionEvent对象传递进去的那些个方法。
搜集数据
当用户把一个或者多个手指放在屏幕上的时候,view的回调函数onTouchEvent()就会被触发。对于每一个系列的触摸事件(位置,压力,大小,其他手指的附加信息)都会最终被定义为一个手势,onTouchEvent()会被调用很多次。
从用户的手指解除屏幕的时候一个手势就会开始,系统会追踪用户的手指们的位置,并捕获用户手指最终离开屏幕的最终事件。在整个交互过程中,MotionEvent会多次传递给onTouchEvent方法中,提供每一交互的细节。你的app通过MotionEvent中提供的数据来判断是不是一个它关注的事件发生了。
捕获一个Activity或者view的触摸事件
想要拦截在Activity或者View中的触摸事件,你要重写onTouchEvent回调方法。
下面的代码片使用getActionMasked()来从event参数中提取用户的行为。这给了你判断你关注的手势是否发生的毛数据。
public class MainActivity extends Activity { ... // This example shows an Activity, but you would use the same approach if // you were subclassing a View. @Override public boolean onTouchEvent(MotionEvent event){ int action = MotionEventCompat.getActionMasked(event); switch(action) { case (MotionEvent.ACTION_DOWN) : Log.d(DEBUG_TAG,"Action was DOWN"); return true; case (MotionEvent.ACTION_MOVE) : Log.d(DEBUG_TAG,"Action was MOVE"); return true; case (MotionEvent.ACTION_UP) : Log.d(DEBUG_TAG,"Action was UP"); return true; case (MotionEvent.ACTION_CANCEL) : Log.d(DEBUG_TAG,"Action was CANCEL"); return true; case (MotionEvent.ACTION_OUTSIDE) : Log.d(DEBUG_TAG,"Movement occurred outside bounds " + "of current screen element"); return true; default : return super.onTouchEvent(event); } }你可以通过自己的程序来处理这些事件来判断是一个手势。如果是一个典型的手势的话,你可能会这么做。但是如果你的app使用例如双击,长安,滑动或者类似的手势,你可以使用一个高级类,GestureDetector类。GestureDetector可以让你不用自己去处理每一个时间,来探测一些通常的手势。在下面的文章Detect Gestures中有详细的讨论。
捕获一个单独的View的触摸事件
一种使用onTouchEvent()的方法是,你可以使用setOnTouchListener的方法来附加一个View.OnTouchListener对象到View对象当中。这使得你可你不用拓展一个view类就可以监听一个触摸事件。例如:
View myView = findViewById(R.id.my_view); myView.setOnTouchListener(new OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { // ... Respond to touch events return true; } });要当心如果创建了一个对于ACTION_DOWN事件返回一个false值的listener。如果你这样做的话,那么后续的ACTION_MOVE和ACTION_UP的一连串事件你都不会再被调用了。这是因为ACTION_DOWM是所有触摸事件的起始事件。
如果你创建了一个自定义的view,你可以如同上面那样重写onTouchEvent方法。
检测手势
android提供了GestureDetector类来检测一般的手势。它支持的手势包括onDown,onLongPress,onFling等等。你可以使用GestureDetector类,和上面的onTouchEvent方法相结合。
检测所有的支持的手势
当你实例化一个GestureDetector对象的时候,你需要传递一个GestureDetector.OnGestureListener接口。GestureDetector.OnGestureListener在特定的触摸事件发生的时候回通知用户。要做到让GestureDetector对象接收事件,你需要重写View或者Activity的onTouchEvent方法,病传输所有的观察到的事件到detetor实例当中。
下面的代码片,在一个onTouchEvent方法中返回了true,只是了你处理了这个触摸事件。如果返回值为false,那么这个事件就会被向下一直传递,直到在view栈当中被成功的处理了。
运行下面的代码来感受一下你在屏幕的触摸是如果触发动作的,以及每一个触摸动作产生的MotionEvent包含的内容。你可以看到每一个简单的交互产生了多少的数据。
public class MainActivity extends Activity implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener{ private static final String DEBUG_TAG = "Gestures"; private GestureDetectorCompat mDetector; // Called when the activity is first created. @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Instantiate the gesture detector with the // application context and an implementation of // GestureDetector.OnGestureListener mDetector = new GestureDetectorCompat(this,this); // Set the gesture detector as the double tap // listener. mDetector.setOnDoubleTapListener(this); } @Override public boolean onTouchEvent(MotionEvent event){ this.mDetector.onTouchEvent(event); // Be sure to call the superclass implementation return super.onTouchEvent(event); } @Override public boolean onDown(MotionEvent event) { Log.d(DEBUG_TAG,"onDown: " + event.toString()); return true; } @Override public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) { Log.d(DEBUG_TAG, "onFling: " + event1.toString()+event2.toString()); return true; } @Override public void onLongPress(MotionEvent event) { Log.d(DEBUG_TAG, "onLongPress: " + event.toString()); } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { Log.d(DEBUG_TAG, "onScroll: " + e1.toString()+e2.toString()); return true; } @Override public void onShowPress(MotionEvent event) { Log.d(DEBUG_TAG, "onShowPress: " + event.toString()); } @Override public boolean onSingleTapUp(MotionEvent event) { Log.d(DEBUG_TAG, "onSingleTapUp: " + event.toString()); return true; } @Override public boolean onDoubleTap(MotionEvent event) { Log.d(DEBUG_TAG, "onDoubleTap: " + event.toString()); return true; } @Override public boolean onDoubleTapEvent(MotionEvent event) { Log.d(DEBUG_TAG, "onDoubleTapEvent: " + event.toString()); return true; } @Override public boolean onSingleTapConfirmed(MotionEvent event) { Log.d(DEBUG_TAG, "onSingleTapConfirmed: " + event.toString()); return true; } }
检测一个支持的手势的子集
如果你想检测而几个手势,你可以继承GestureDetector.SimpleOnGesureListener,来替代GestureDetector.OnGestureListener接口。
GestureDetector.SimpleOnGestureListener提供一个所有的on<Touch>方法实现,每一个中的返回值都是false。这样你可以只重写你关心的方法。例如,下面的代码片创建了一个继承于Gesture.SimpleOnGestureListener,并重写了onFling()和onDown()方法。
无论你是否使用了GestureDetecor.OnGestureListener类,实现一个onDown方法并返回true都是最好的做法。这是因为所有的手势都是以一个onDown消息开始的。如果你在onDown中返回了false,那么按照GestrueDitector.SimpleOnGestureDetector的默认情况,系统会认为你想要忽略其他的手势,二其他的GestureDetector.OnGestureListener的方法就不再会被调用。这可以在你app中一起一个潜在的意外问题。为你你想要在onDown中返回false的情况就是你确定你想要忽略掉整个手势的时候。
public class MainActivity extends Activity { private GestureDetectorCompat mDetector; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mDetector = new GestureDetectorCompat(this, new MyGestureListener()); } @Override public boolean onTouchEvent(MotionEvent event){ this.mDetector.onTouchEvent(event); return super.onTouchEvent(event); } class MyGestureListener extends GestureDetector.SimpleOnGestureListener { private static final String DEBUG_TAG = "Gestures"; @Override public boolean onDown(MotionEvent event) { Log.d(DEBUG_TAG,"onDown: " + event.toString()); return true; } @Override public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) { Log.d(DEBUG_TAG, "onFling: " + event1.toString()+event2.toString()); return true; } } }