传递Touch事件
Touch事件是由Linux内核的一个Input子系统来管理的(InputManager),Linux子系统会在 /dev/input/ 这个路径下创建硬件输入设备节点(这里的硬件设备就是我们的触摸屏了)。当手指触动触摸屏时,硬件设备通过设备节点向内核(其实是InputManager管理)报告事件,InputManager 经过处理将此事件传给 Android系统的一个系统Service: WindowManagerService 。
Touch 事件传递的基本的规则:
1、 down事件首先会传递到onInterceptTouchEvent()方法
2、如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return false,那么后续的move, up等事件将继续会先传递给该ViewGroup,之后才和down事件一样传递给最终的目标view的onTouchEvent()处理。
3、如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return true,那么后续的move, up等事件将不再传递给onInterceptTouchEvent(),而是和down事件一样传递给该ViewGroup的onTouchEvent()处理,注意,目标view将接收不到任何事件。
4、如果最终需要处理事件的view的onTouchEvent()返回了false,那么该事件将被传递至其上一层次的view的onTouchEvent()处理。
5、 如果最终需要处理事件的view 的onTouchEvent()返回了true,那么后续事件将可以继续传递给该view的onTouchEvent()处理。
示例图解释 touch 时间传递过程:
Case 0 : onInterceptTouchEvent()处理down事件均返回false,onTouchEvent()处理事件均返回true
04-06 02:28:38.085 19815-19815/com.owenchan D/ParentLayout: [onInterceptTouchEvent] -> ACTION_DOWN
04-06 02:28:38.085 19815-19815/com.owenchan D/ChildLayout: [onInterceptTouchEvent] -> ACTION_DOWN
04-06 02:28:38.085 19815-19815/com.owenchan D/MyTextView: [onTouchEvent] -> ACTION_DOWN
04-06 02:28:38.227 19815-19815/com.owenchan D/ParentLayout: [onInterceptTouchEvent] -> ACTION_MOVE
04-06 02:28:38.227 19815-19815/com.owenchan D/ChildLayout: [onInterceptTouchEvent] -> ACTION_MOVE
04-06 02:28:38.228 19815-19815/com.owenchan D/MyTextView: [onTouchEvent] -> ACTION_MOVE
......
...... //省略过多的ACTION_MOVE
......
04-06 02:28:38.654 19815-19815/com.owenchan D/ParentLayout: [onInterceptTouchEvent] -> ACTION_UP
04-06 02:28:38.654 19815-19815/com.owenchan D/ChildLayout: [onInterceptTouchEvent] -> ACTION_UP
04-06 02:28:38.654 19815-19815/com.owenchan D/MyTextView: [onTouchEvent] -> ACTION_UP
onInterceptTouchEvent并没有做任何改变事件传递时序的操作,效果上和没有覆写该方法是一样的。可以看到,各种事件的传递本身是自底向上的,次序是:ParentLayout->ChildLayout->MyTextView。注意,在onInterceptTouchEvent均返回false时,ParentLayout和ChildLayout的onTouchEvent并不会收到事件,而是最终传递给了MyTextView。
Case 1: ParentLayout的onInterceptTouchEvent()处理down事件返回true,MyTextView的onTouchEvent()处理事件返回true
04-06 02:39:25.878 28073-28073/com.owenchan D/ParentLayout: [onInterceptTouchEvent] -> ACTION_DOWN
04-06 02:39:25.878 28073-28073/com.owenchan D/ParentLayout: [onTouchEvent] -> ACTION_DOWN
04-06 02:39:26.092 28073-28073/com.owenchan D/ParentLayout: [onTouchEvent] -> ACTION_MOVE
......
......//省略过多的ACTION_MOVE
......
04-06 02:39:26.403 28073-28073/com.owenchan D/ParentLayout: [onTouchEvent] -> ACTION_UP
由于ParentLayout在拦截第一次down事件时return true,所以后续的事件(包括第一次的down)将由ParentLayout 本身的onTouchEvent 处理,事件不再传递下去。
Case 2 ParentLayout,ChildLayout的onInterceptTouchEvent()处理down事件返回false,MyTextView的onTouchEvent()处理事件返回false
ChildLayout的onTouchEvent()处理事件返回true
04-06 02:54:03.557 8333-8333/com.owenchan D/ParentLayout: [onInterceptTouchEvent] -> ACTION_DOWN
04-06 02:54:03.557 8333-8333/com.owenchan D/ChildLayout: [onInterceptTouchEvent] -> ACTION_DOWN
04-06 02:54:03.557 8333-8333/com.owenchan D/MyTextView: [onTouchEvent] -> ACTION_DOWN
04-06 02:54:03.558 8333-8333/com.owenchan D/ChildLayout: [onTouchEvent] -> ACTION_DOWN
04-06 02:54:03.855 8333-8333/com.owenchan D/ParentLayout: [onInterceptTouchEvent] -> ACTION_MOVE
04-06 02:54:03.855 8333-8333/com.owenchan D/ChildLayout: [onTouchEvent] -> ACTION_MOVE
04-06 02:54:03.856 8333-8333/com.owenchan D/ParentLayout: [onInterceptTouchEvent] -> ACTION_MOVE
04-06 02:54:03.856 8333-8333/com.owenchan D/ChildLayout: [onTouchEvent] -> ACTION_MOVE
04-06 02:54:03.996 8333-8333/com.owenchan D/ParentLayout: [onInterceptTouchEvent] -> ACTION_UP
04-06 02:54:03.996 8333-8333/com.owenchan D/ChildLayout: [onTouchEvent] -> ACTION_UP
可以看到,由于MyTextView在onTouchEvent()中return false,down事件被传递给其父view,即LayoutView2的onTouchEvent()方法处理,由于在LayoutView2的onTouchEvent()中return true,所以down事件传递并没有上传到LayoutView1。注意,后续的move和up事件均被传递给LayoutView2的onTouchEvent()处理,而没有传递给MyTextView。
Demo代码地址 :https://github.com/chenzongwen/AndroidTouchDemo.git