为什么需要手势识别?
手势对于我们的app有很多的地方都在使用,比如右滑关闭界面等。手势控制分为触发动作(Touch Mechanics,用户手指在屏幕上如何动作)和触发行为(Touch Activities,界面上特定动作在特定情境下引发的结果)。这是因为同样的触发动作(如单次触击)在不同情境下可能会带来不同的结果(如轻触,取消,开启/关闭指示),同样单次触发行为(如放大)可能是由多种触发动作(如捏放,双次触击,双次触击拖拽等)实现。
一般情况下,我们知道View类有个View.OnTouchListener内部接口,通过
重写他的onTouch(View v, MotionEvent event)
方法,我们可以处理一些touch事件,但是这个方法太过简单,如果需要处理一些复杂的手势,用这个接口就会很麻烦(因为我们要自己根据用户触摸的轨迹去判断是什么手势)。
Android
sdk给我们提供了
GestureDetector
类,通过这个类我们可以识别很多的手势,主要是通过他的onTouchEvent(event)方法完成了不同手势的识别。虽然他能识别手势,但是不同的手势要怎么处理,应该是提供给程序员实现的。
GestureDetector这个类对外提供了两个接口和一个外部类,用于监听不同的手势
接口: OnGestureListener, OnDoubleTapListener
内部类: SimpleOnGestureListener
1、实现
GestureDetector.OnGestureListener
private class gesturelistener implements GestureDetector.OnGestureListener{
public boolean onDown(MotionEvent e) {
// TODO Auto-generated method stub
return false;
public void onShowPress(MotionEvent e) {
// TODO Auto-generated method stub
public boolean onSingleTapUp(MotionEvent e) {
// TODO Auto-generated method stub
return false;
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
// TODO Auto-generated method stub
return false;
public void onLongPress(MotionEvent e) {
// TODO Auto-generated method stub
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
// TODO Auto-generated method stub
return false;
实现该接口时,需要重载六个函数。 下面讲解一下这六个函数的触发条件(具体参看源码中的注释):
OnDown(MotionEvent e):用户按下屏幕就会触发;
onShowPress(MotionEvent e):如果是按下的时间超过瞬间,而且在按下的时候没有松开或者是拖动的,那么onShowPress就会执行。官方的注释如下:
* The user has performed a down {@link MotionEvent} and not performed
* a move or up yet. This event is commonly used to provide visual
* feedback to the user to let them know that their action has been
* recognized i.e. highlight an element.
* @param e The down motion event
onLongPress(MotionEvent e):长按触摸屏,超过一定时长,就会触发这个事件
触发顺序:
onDown->onShowPress->onLongPress
onSingleTapUp(MotionEvent e):从名子也可以看出,一次单独的轻击抬起操作,也就是轻击一下屏幕,立刻抬起来,才会有这个触发,当然,如果除了Down以外还有其它操作,那就不再算是Single操作了,所以也就不会触发这个事件
触发顺序:
点击一下非常快的(不滑动)Touchup:
onDown->onSingleTapUp->onSingleTapConfirmed
点击一下稍微慢点的(不滑动)Touchup:
onDown->onShowPress->onSingleTapUp->onSingleTapConfirmed
onFling(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY) :滑屏,用户按下触摸屏、快速移动后松开,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE, 1个ACTION_UP触发
参数解释:(当滑动屏幕的速度较慢时,该方法不会被调用)
e1:第1个ACTION_DOWN MotionEvent
e2:最后一个ACTION_MOVE MotionEvent
velocityX:X轴上的移动速度,像素/秒
velocityY:Y轴上的移动速度,像素/秒
注: 可以通过该函数里的滑动距离和滑动速度,判断是左滑还是右滑
onScroll(MotionEvent e1, MotionEvent e2,float distanceX, float distanceY):在屏幕上拖动事件。无论是用手拖动view,或者是以抛的动作滚动,都会多次触发,这个方法 在ACTION_MOVE动作发生时就会触发
滑屏:手指触动屏幕后,稍微滑动后立即松开
onDown-----》onScroll----》onScroll----》onScroll----》………----->onFling
拖动(当滑动的速度不是很快的时候,onFling函数最后不会被调用。)
onDown------》onScroll----》onScroll
2、实现OnDoubleTapListener
/**
* The listener that is used to notify when a double-tap or a confirmed
* single-tap occur.
*/
OnGestureListener实现了单击相关的手势识别,对于双击相关的手势识别需要单独实现,下面具体介绍里面的几个方法:
private GestureDetector.OnDoubleTapListener mOnDoubleTapListener = new GestureDetector.OnDoubleTapListener() {
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
logger("onSingleTapConfirmed:");
return false;
@Override
public boolean onDoubleTap(MotionEvent e) {
logger("onDoubleTap:");
return false;
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
logger("onDoubleTapEvent:"+MotionEvent.actionToString(e.getAction()));
return false;
onSingleTapConfirmed(MotionEvent e):单击事件。用来判定该次点击是SingleTap而不是DoubleTap,如果连续点击两次就是DoubleTap手势,如果只点击一次,系统等待一段时间后没有收到第二次点击则判定该次点击为SingleTap而不是DoubleTap,然后触发SingleTapConfirmed事件。触发顺序是:OnDown->OnsingleTapUp->OnsingleTapConfirmed
关于onSingleTapConfirmed和onSingleTapUp的一点区别: OnGestureListener有这样的一个方法onSingleTapUp,和onSingleTapConfirmed容易混淆。二者的区别是:onSingleTapUp,只要手抬起就会执行,而对于onSingleTapConfirmed来说,如果双击的话,则onSingleTapConfirmed不会执行。
onDoubleTap(MotionEvent e):双击事件
onDoubleTapEvent(MotionEvent e):双击间隔中发生的动作。指触发onDoubleTap以后,在双击之间发生的其它动作,包含down、up和move事件;下图是双击一下的Log输出:
3、实现SimpleOnGestureListener
* A convenience class to extend when you only want to listen for a subset
* of all the gestures. This implements all methods in the
* {@link OnGestureListener}, {@link OnDoubleTapListener}, and {@link OnContextClickListener}
* but does nothing and return {@code false} for all applicable methods.
public static class SimpleOnGestureListener implements OnGestureListener, OnDoubleTapListener,OnContextClickListener{…..}
它与前两个不同的是:
1、这是一个类,在它基础上新建类的话,要用extends派生而不是用implements继承!
2、OnGestureListener和OnDoubleTapListener接口里的函数都是强制必须重写的,即使用不到也要重写出来一个空函数但在SimpleOnGestureListener类的实例或派生类中不必如此,可以根据情况,用到哪个函数就重写哪个函数,因为SimpleOnGestureListener类本身已经实现了这两个接口的所有函数,只是里面全是空的而已。
4、通过兼容包中工具识别手势
GestureDetector属于android.view包,android还提供了android.gesture包支持更多的手势操作。官方的介绍中使用了GestureDetectorCompat处理手势识别。 在识别手势的时候尽量使用 兼容包中手势识别。
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;
View Code
有两个构造方法:一个构造方法入上述手势识别的代码,另一种增加了一个Handler参数,如下:
梦想不是浮躁,而是沉淀和积累