http://blog.csdn.net/u010410408/article/details/39577399
GestureDetector
概述
该类主要是用于识别一些特定的手势,我们只需要调用GestureDetector.onTouchEvent(),并把MotionEvent传递进去即可。对于各种手势的回调,可以通过GestureDetector中的接口OnGestureListener来完成。
只需要在View#onTouchEvent()中调用GestureDetector#onTouchEvent()即可。
OnGestureListener
onDown
在GestureDetector.onTouchEvent()中,当action_down发生时,该方法肯定会立即被调用。源码为:
从中可以看出action_down事件发生时,一定会触发onDown()事件。而隔了TAG_TIMEOUT后才会触发onShowPress();隔TAP_TIMEOUT+LONGPRESS_TIMEOUT后才会触发onLongPress()。GestureDetector.onTouchEvent()的返回值就是最后一句中的handled,而在每一次调用该方法时handled都会被初始化成false。因此,该方法最终会影响onTouchEvent()的返回值,如果onDown()返回true,那么onTouchEvent()一定会返回true;反之不一定返回false(因为省略的部分对handled进行了修改)。
onShowPress
在action_down时,会通过handler发送一个消息(SHOW_PRESS),代码为: 从这行代码可以看出,在down事件发生时,并不会立即执行onShowPress(),会等待一段时间后才执行。并且如果在该时间段内,发生了action_move,action_up或者ACTION_CANCEL,还会取消执行该方法。因此,该方法就是在用户真正进行按下事件时才执行,并不是ACTION_DOWN时。因为ACTION_DOWN后,用户可能进行move也可能进行press。onDown()会在action_down事件时就执行,无论该次触摸会发展成press还是scroll。而onShowPress只有在事件是press(按下足够长的时间,并且没有大范围移动)时才会执行,在该方法中一般用来提示用户你已按下,而不能用来单击事件的操作,因为有可能会发现成onLongPress。
onLongPress
与onShowPress()类似,只不过按的时候长时执行onLongPress,时间短时执行onShowPress()。从onDown中的源码可以看出,当mIsLongpressEnabled=true时,才有可能执行onLongPress()。
在new GestureDetector时,该值默认设置为true。可以通过setIsLongpressEnabled()进行设置。
onSingleTapUp
在GestureDetector.onTouchEvent()中,只有在action_up时,才会有可能执行该方法。但是它并不等价于action_up事件。源码如下:从中可以看出,只有当mIsDoubleTapping=false,mInLongPress=false且mAlwaysInTapRegion=true时才会执行。
在源码中可以看到,当移动的距离过大(移动距离超出以ACTION-DOWN时为圆心,以ViewConfiguration.get(context).getScaledTouchSlop();为半径的圆时,移动距离就过大)时mAlwaysInTapRegion = false,或者当点击的时间太长时mInLongPress = true,当为双击事件时,mIsDoubleTapping为true,此时都不会执行onSingleTapUp()。因此,该方法在短单击事件抬起时执行,而且它的MotionEvent中只有Action_UP事件。
注:ViewConfiguration.get(context).getScaledTouchSlop()的返回值经常用来判断是移动还是点击。用户按下后,肯定会不停的抖动,抖动的过程中会不断地触发ACTION_MOVE。如果直接将两次ev.getX(),ev.getY()不一样就认为是滑动的话,显然是不合理的。合理的做法是:当两次ev.getX(),ev.getY()的距离够大才认为是滑动,而ViewConfiguration.get(context).getScaledTouchSlop()就是对这个距离的判断标准。
onScroll
当有滚动时,执行该方法。对该方法的调用都出现在action_move中,代码为: 对于mAlwaysInTapRegion,当action_down时,它会被设置为true。以后只要移动距离不过大,mAlwaysInTapRegion就会一直为true。这也是一般处理点击和滑动的方式:只要移动范围过大了,就不会再认为是点击。只要移动范围不过大,都认为是点击中,不论调用几次action_move。onFling
手指离开屏幕,且滑动速度足够快时调用且仅调用一次该方法。注意:这个方法并不是当屏幕滚动时调用的。
从中可以看到只有当x轴速度或y轴速度大于相应的值时,才会调用onFling()。OnDoubleTapListener
它是GestureDetector中的另一个接口,主要用来处理双击事件。可以通过调用setOnDoubleTapListener()进行设置,也可以在new GestureDetector()时传入SimpleOnGestureListener。
onSingleTapConfirmed
当确定该事件为短单击事件时执行该方法。它与OnGestureListener.onSingleTapUp类似,但是又有不同。onSingleTapUp当一次短点击事件执行到action_up时就会执行;而onSingleTapConfirmed却是在确定该次短点击事件是一次单击事件时才会执行,如果是双击事件就不会执行。 当我们双击时,只会执行onSingleTapUp,不会执行onSingleTapConfirmed;当我们单击时,两者都会执行。
onDoubleTap
双击时,第二次touch事件的down发生时就会执行。因此该MotionEvent中只有action_down。因为该方法只有在action_down中被调用。onDoubleTapEvent
该方法与onDoubleTap类似,只不过它的参数中含有action_up,action_down,action_move事件。它的源码是:action_down时:
从这里可以看出:先调用onDoubleTap再调用onDoubleTapEvent。action_move时:
从中可以看出:只有当mIsDoubleTapping = true时,才会执行该方法。而mIsDoubleTapping = true的唯一一个地方就是上面action_down中的代码。而action_up也类似于action_move。
因此,可以看出:onDoubleTapEvent的执行后于onDoubleTap,并且它的MotionEvent中的down,move与up都是在双击事件中的第二击中的。
总结
单击:选择onSingleTapUp。
长按:选择onLongPress。
展示按下效果:选择onShowPress()——该方法中有show,主要就是用来展示效果的。不能在该方法中处理单击事件,因为有可能会发展成LongPress。
拖动:选择onScroll。
快速滑动:选择onFling。
双击:选择onDoubleTap。这种选择也不好,但几个方法中最好的。
ScaleGestureDetector
概述
用于处理缩放的工具类,用法与GestureDetector类似,都是通过onTouchEvent()关联相应的MotionEvent的。使用该类时,用户需要传入一个完整的连续不断地motion事件(包含ACTION_DOWN,ACTION_MOVE和ACTION_UP事件)。
OnScaleGestureListener
ScaleGestureDetector中的回调接口。主要有三个方法。
onScale
缩放时。返回值代表本次缩放事件是否已被处理。如果已被处理,那么detector就会重置缩放事件;如果未被处理,detector会继续进行计算,修改getScaleFactor()的返回值,直到被处理为止。因此,它常用在判断只有缩放值达到一定数值时才进行缩放。例如:
当进行放大时它的输出结果为:
从中可以看出getScaleFactor()返回的值由小变大,直到大于2后又从1开始变大。这是因为,当缩放因子(getScaleFactor()的返回值)小于2时,onScale()返回的是false,此时detector认为本次缩放尚未结束,所以再次计算缩放因子时仍旧以上次结束时为基准,这样就导致了手指外移时缩放参数越来越大;当达到2后,本次缩放结束,再次获得缩放因子时的基准就变成刚刚结束的位置了,因此,获取的缩放因子会猛然变小(因为手指外移,执行的是放大操作,所以缩放因子会大于1)。
onScaleBegin
缩放开始。该detector是否处理后继的缩放事件。返回false时,不会执行onScale()。
onScaleEnd
缩放结束时。
常用方法
onTouchEvent():关联MotionEvent。返回true代表该detector想继续接收后继的motion事件;否则反之。默认时该方法返回true。
getScaleFactor():获取本次缩放事件的缩放因子(缩放事件以onScale()返回值为基准,一旦该方法返回true,代表本次事件结束,要开启下次事件)。它的返回值是指本次事件中的缩放值,并不是相对于最开始的值。如一张图片开始放大2倍,后来又放大1.1倍。那么第二次放大时,该方法返回的就是1.1,而不是总放大倍数:2*1.1。
getCurrentSpan(): 返回手势过程中,组成该手势的两个触点的当前距离。返回值以像素为单位的触点距离。
getCurrentSpanX(),getCurrentSpanY():跟getCurrentSpan()类似,只不过一个是返回的是x轴上的距离,一个是y轴上的距离。注意:返回值有可能为负数。这两个方法的返回值和getCurrentSpan()的返回值满足勾股定理。
getFocusY(),getFocusX():返回组成该手势的两个触点的中点在组件上的y,x轴坐标,单位为像素。
getPreviousSpan():返回缩放过程中,组成当前缩放手势的两个触点的前一次距离。假设有a,b,c三个手指,某一次a,b组成缩放手势,两者的距离是300;随后一直是b,c组成缩放手势,当c抬起时,b,c的距离时100。此时,ab会组成缩放手势,该值返回的就是300,而不是b,c的100。
getPreviousSpanX(),getPreviousSpanY():同getPreviousSpan()类似。
getEventTime():获取当前motion事件的时间。源码如下:
getTimeDelta():返回上次缩放事件结束时到当前的时间间隔。见下图:
开始是1586,下一次立刻变成了10。这是因为在1586时,onScale返回了true,detector认为本次缩放事件已结束,再获取deltatime时就重新开始计算,所以值陡然变减少变成10。
isInProgress():如果缩放手势正处在进行中,返回true;否则返回false。