触摸事件分发:就是一个为了解决触摸事件冲突而设置的机制
1.事件类型
ACTION_DOWN -> ACTION_UP / ACTION_CANCEL
ACTION_DOWN -> ACTION_MOVE -> ACTION_MOVE -> ACTION_MOVE -> ACTION_UP / ACTION_CANCEL
这个取消事件ACTION_CANCEL它是一种特殊的事件,它对应的是时间序列的非人为的提前结束
2.onTouchEvent()
在Android里面,每一个触摸事件都会交给View的onTouchEvent()方法来处理
当用户的手指刚刚触摸到屏幕的时候,也就是一个事件组第一个事件DOWN发生的时候,Android会从用户的触摸点上离用户最近的那个View开始,向下一个一个地去调用每一个View的onTouchEvent(),如果View的onTouchEvent()对这个Down事件没有响应,它就会继续向下,直到遇到第一个做出响应的View,这个向下的过程才会结束。这个时候,这个View就成为了这组事件的接收者,这个DOWN事件的后续事件都会直接发送给它,不会给它上面的View,也不会给它下面的View,直到这组事件结束,也就是UP事件或者CANCEL事件出现
View是否响应DOWN事件,其实取决于onTouchEvent()的返回值是否为true。其实只有DOWN事件的返回值需要是true,像后续事件UP或者MOVE它们的返回值是没有影响的。但是如果要自定义,全都写成true不是挺方便的吗
如果想要写自己的触摸反馈算法,只要重写onTouchEvent()在里面写自己的算法,然后返回true就好了
3.onInterceptTouchEvent()
它用于触摸事件分发里面的事件拦截机制
在用户触摸屏幕的时候,每一个触摸事件到达View的onTouchView()之前,Android会从整个Activity里面最底部的那个根View,向上一级一级地询问:你要不要拦截这组事件,如果整个流程走完,所有的ViewGroup都不拦截,这个时候就会走第二个流程:onTouchEvent() 从上往下。而如果中途某个View拦截事件,那么这个事件就不会再发给它的子View,而是直接转交给它自己的onTouchEvent()来处理,并且在这之后的这个事件组的所有后续事件就全部都会被自动拦截了,不会再交给它的子View,也不会交给它的onInterceptTouchEvent(),而是直接交给它的onTouchEvent()
ViewGroup是否拦截事件,是通过调用 ViewGroup 的 onInterceptTouchEvent() 方法来实现的,返回true表示拦截
当onInterceptTouchEvent()返回true的时候,除了完成事件接管,它还会对它的子View发送一个额外的取消事件CANCEL,通知子View恢复状态
另外onInterceptTouchEvent()和onTouchEvent()有一点不同在于,onTouchEvent()是否要消费这组事件是需要在DOWN事件中决定的,如果在DOWN事件发过来的时候返回了false,那么以后你就跟这组事件无缘了,没有第二次机会;而onInterceptTouchEvent()则是你在整个过程中都可以对事件流中的每个事件进行监听,随时可以返回true,来对事件流进行接管。
所以如果要写一个可以滑动或者捏撑的ViewGroup,那么除了重写onTouchEvent()来处理事件,还需要重写onInterceptTouchEvent(),在DOWN事件的时候返回false,然后在后续事件中,在你觉得合适的时候,返回true来实现事件的拦截接管
4.requestDisallowInterceptTouchEvent()
在事件过程中在子View里面,调用父View的requestDisallowInterceptTouchEvent(true),例如getParent().requestDisallowInterceptTouchEvent(true),父View在这个事件流中就不会再通过onInterceptTouchEvent()来尝试拦截了,并且它是一个递归方法,它会阻止每一级父View的拦截,不过仅限于当前事件流
5.dispatchTouchEvent()
它是事件分发的总的调度方法,onTouchEvent() 和 onInterceptTouchEvent() 其实都是在dispatchTouchEvent()里面发生的,一个事件分发的过程,实质上就是从根View递归地调用了一次dispatchTouchEvent() 的过程
参考文章:
HenCoder 自定义 View 3-1 触摸反馈,以及 HenCoder Plus