为什么要解读触摸事件分发机制
1.掌握View事件分发机制
2.为解决View滑动冲突提供理论支持
3.了解Android最新源码改动
Touch触摸事件
在Android中Touch触摸事件主要包括点击(onClick)、长按(onLongClick)、拖拽(onDrag)、滑动(onScroll)等,点击又包括单击和双击,另外还包括单指操作和多指操作。其中Touch的第一个状态是 ACTION_DOWN,表示按下了屏幕后,touch将会有后续事件,比如移动、抬起等,一个Action_DOWN,一个ACTION_UP,许多个ACTION_MOVE,就构成了Android中众多的事件。所有的操作事件首先必须执行的是按下操作(ACTIONDOWN),之后所有的操作都是以此作为前提,当按下操作完成后,接下来可能是一段移动(ACTIONMOVE)然后抬起(ACTION_UP),或者是按下操作执行完成后没有移动就直接抬起。
● 按下(ACTION_DOWN)
● 移动(ACTION_MOVE)
● 抬起(ACTION_UP)
● 取消手势(ACTION_CANCEL)
● 滑出屏幕(ACTION_OUTSIDE)
Android中的Touch事件都是从ACTION_DOWN开始的:
单指操作:ACTION_DOWN---ACTION_MOVE----ACTION_UP
多指操作:ACTION_DOWN---ACTION_POINTER_DOWN---ACTION_MOVE--ACTION_POINTER_UP---ACTION_UP.
- 1
- 2
触摸事件分发机制涉及的三个重要方法
public boolean dispatchTouchEvent(MotionEvent ev)
- 1
dispatchTouchEvent用来进行事件的分发。如果事件能够传递给当前的View,那么此方法一定会被调用,返回结果受当前View的onTouchEvent和下级View的dispatchTouchEvent方法的影响,表示是否消耗当前事件。
public boolean onInterceptTouchEvent(MotionEvent event)
- 1
onInterceptTouchEvent是ViewGroup提供的方法,用来判断是否拦截某个事件,如果当前View拦截了某个事件,那么在同一个事件序列当中,此方法不会被再次调用,返回结果表示是否拦截当前事件。默认返回false,返回true表示拦截。
public boolean onTouchEvent(MotionEvent event)
- 1
onTouchEvent在dispatchTouchEvent方法中调用,用来处理点击事件,返回结果表示是否消耗当前的事件,如果不消耗,则在同一个事件序列中,当前View无法再次接受到事件。view中默认返回true,表示消费了这个事件。
这三个重要方法的分布情况
在View中包含以下两个方法:
public boolean dispatchTouchEvent(MotionEvent ev);
public boolean onTouchEvent(MotionEvent ev);
在ViewGroup中包含以下三个方法:
public boolean dispatchTouchEvent(MotionEvent ev);
public boolean onInterceptTouchEvent(MotionEvent ev);
public boolean onTouchEvent(MotionEvent ev);
在Activity中包含以下两个方法:
public boolean dispatchTouchEvent(MotionEvent ev);
public boolean onTouchEvent(MotionEvent ev);
Android触摸事件分发流程图
Android触摸事件流程总结
1.一个事件序列是指从手指触摸屏幕开始,到手指离开屏幕结束,这个过程中产生的一系列事件。同一个事件序列是以ACTION_DOWN事件开始,中间含有数量不定的MOVE事件,最终以ACTION_UP事件结束。
2.事件传递的顺序是:Activity->Window->View,即事件总是先传递给Activity,然后在传递给Window,最后在传递给View,顶级View接收到事件后,就会按照事件分发机制去分发事件。
3.事件的传递过程是由外向内的,即事件总是由父元素分发给子元素。
4.正常情况下,一个事件序列只能被一个View拦截且消耗。一旦一个元素拦截了某次事件,那么同一个事件序列内的所有事件都会直接交给它处理,因此同一个事件序列中的事件不能分别由两个View同时处理,但是通过特殊手段可以做到,比如一个View将本该自己处理的事件通过onTouchEvent强行传递给其他View处理。
5.某个View一旦开始处理事件,如果它不消耗ACTION_DOWN事件,那么同一事件序列的其他事情都不会再交给它来处理,并且事件将重新交给它的父容器去处理(调用父容器的onTouchEvent方法);如果它消耗ACTION_DOWN事件,但是不消耗其他类型事件,那么这个点击事件会消失,父容器的onTouchEvent方法不会被调用,当前view依然可以收到后续的事件,但是这些事件最后都会传递给Activity处理。
6.Android点击事件分发是到达顶级View后(一般是ViewGroup),会调用ViewGroup的dispatchTouchEvent方法,其中它的onInterceptTouchEvent方法如果返回true,则会对事件传递进行拦截,事件由ViewGroup处理;如果onInterceptTouchEvent方法返回false,则代表不对事件进行拦截,默认返回false。则此时子View中的dispatchTouchEvent方法将被调用,到此,事件已经由顶级View传递给了下一层的View,接下来的过程是一个递归循环的过程,和顶级View事件分发过程是一致的,直到完成整个事件分发。