一个最简单的屏幕触摸动作,理解事件分发的3个方法
前言
android中的事件类型分为按键事件和屏幕触摸事件,Touch事件是屏幕触摸事件的基础事件。
一次屏幕触摸会发生什么?
触发了一系列Touch事件:ACTION_DOWN->ACTION_MOVE->ACTION_MOVE->ACTION_MOVE…->ACTION_MOVE->ACTION_UP。到底有多少个MOVE呢?我也不知道,我写demo测试的时候点击一下是打印了3条。
当屏幕中包含一个ViewGroup,而这个ViewGroup又包含一个子view,这个时候android系统如何处理Touch事件呢?到底是ViewGroup来处理Touch事件,还是子view来处理Touch事件呢?先留个疑问。
解决疑问前,先要理清楚ViewGroup这个类中,和TouchEvent处理密切相关的3个方法:
- public boolean dispatchTouchEvent(MotionEvent ev) 这个方法用来分发TouchEvent
- public boolean onInterceptTouchEvent(MotionEvent ev) 这个方法用来拦截TouchEvent(这个方法在View类中没有)
- public boolean onTouchEvent(MotionEvent ev) 这个方法用来处理TouchEvent
接下来我们来理一下逻辑
当TouchEvent发生时,首先交互界面(Activity或者Fragment)将TouchEvent传递给最顶层的View, TouchEvent最先到达最顶层 view 的 dispatchTouchEvent ,然后由dispatchTouchEvent 方法进行分发,如果dispatchTouchEvent返回true ,就不往下传递了,如果dispatchTouchEvent返回 false ,则交给这个 view 的 interceptTouchEvent 方法来决定是否要拦截这个事件,如果 interceptTouchEvent 返回 true ,也就是拦截掉了,则交给它的 onTouchEvent 来处理,如果 interceptTouchEvent 返回 false ,那么就传递给子 view ,由子 view 的 dispatchTouchEvent 再来开始这个事件的一次分发。如果事件传递到某一层, 被onTouchEvent 处理了,那这一次事件算是结束了。
看一道小米的面试题
先回忆一下之前的知识
1、最开始接收事件的是最外层的对象。
2、最外层对象会依次调用dispatchTouchEvent 、onInterceptTouchEvent 。(一般情况:有儿子View,分发+不拦截)
3、事件传递到某层的儿子View,onTouchEvent处理了。
问题解答
ACTION_DOWN在3个界面传递;ACTION_MOVE在A、B界面传递,B拦截了并调用onTouchEvent处理了。ACTION_UP在A、B界面传递。
问题分析
ACTION_DOWN没有限制;ACTION_MOVE到B的时候由于onInterceptTouchEvent拦截了,被B处理,C收不到;ACTION_UP由于B拦截了MOVE,已经处理了,也会直接在B调用onTouchEvent处理。
打印日志
A
12-05 18:03:18.871 6113-6113/com.phz.testtouchevent E/ALayout: dispatchTouchEvent:ACTION_DOWN
12-05 18:03:18.871 6113-6113/com.phz.testtouchevent E/ALayout: onInterceptTouchEvent:ACTION_DOWN
12-05 18:03:18.889 6113-6113/com.phz.testtouchevent E/ALayout: dispatchTouchEvent:ACTION_MOVE
12-05 18:03:18.889 6113-6113/com.phz.testtouchevent E/ALayout: onInterceptTouchEvent:ACTION_MOVE
12-05 18:03:18.906 6113-6113/com.phz.testtouchevent E/ALayout: dispatchTouchEvent:ACTION_MOVE
12-05 18:03:18.906 6113-6113/com.phz.testtouchevent E/ALayout: onInterceptTouchEvent:ACTION_MOVE
12-05 18:03:18.909 6113-6113/com.phz.testtouchevent E/ALayout: dispatchTouchEvent:ACTION_UP
12-05 18:03:18.910 6113-6113/com.phz.testtouchevent E/ALayout: onInterceptTouchEvent:ACTION_UP
B
12-05 18:03:18.871 6113-6113/com.phz.testtouchevent E/BLayout: dispatchTouchEvent:ACTION_DOWN
12-05 18:03:18.871 6113-6113/com.phz.testtouchevent E/BLayout: onInterceptTouchEvent:ACTION_DOWN
12-05 18:03:18.889 6113-6113/com.phz.testtouchevent E/BLayout: dispatchTouchEvent:ACTION_MOVE
12-05 18:03:18.889 6113-6113/com.phz.testtouchevent E/BLayout: onInterceptTouchEvent:ACTION_MOVE
12-05 18:03:18.906 6113-6113/com.phz.testtouchevent E/BLayout: dispatchTouchEvent:ACTION_MOVE
12-05 18:03:18.906 6113-6113/com.phz.testtouchevent E/BLayout: onTouchEvent:ACTION_MOVE
12-05 18:03:18.910 6113-6113/com.phz.testtouchevent E/BLayout: dispatchTouchEvent:ACTION_UP
12-05 18:03:18.910 6113-6113/com.phz.testtouchevent E/BLayout: onTouchEvent:ACTION_UP
C
12-05 18:03:18.871 6113-6113/com.phz.testtouchevent E/CLayout: dispatchTouchEvent:ACTION_DOWN
12-05 18:03:18.871 6113-6113/com.phz.testtouchevent E/CLayout: onTouchEvent:ACTION_DOWN