触摸事件传递机制
本文最后更新于:1 年前
触摸事件传递的三个阶段
分发
分发对应dispatchTouchEvent()
方法。
如果当前视图是ViewGroup
及其子类,则会调用onInterceptTouchEvent()
方法判断是否拦截该事件。
该方法返回true
或false
表示该事件被当前视图分发过,不继续分发该事件给子视图,其中true
表示该事件被当前视图消费掉,false
表示该事件未被当前视图消费掉;返回super.dispatchTouchEvent()
表示继续分发该事件给子视图。
该事件将会按照嵌套层次从外向内传递,到达最内层的视图时,由该视图的onTouchEvent()
方法处理,如果该方法能消费该事件,则返回true
,如果消费不了,返回false
,这时事件开始按照嵌套层次从内向外传递,并由外层的视图的 onTouchEvent()
方法进行尝试消费,其中,返回true
为消费完毕,返回false
为未消费,可继续向外层传递。
拦截
拦截对应onInterceptTouchEvent()
方法。
该方法只在ViewGroup
及其子类中存在,在Activity
和View
中不存在。
该方法返回true
表示拦截该事件,不继续分发给子视图,同时交给自身的onTouchEvent()
方法进行尝试消费,其中,返回true
为消费完毕,返回false
为未消费,可继续向外层传递;返回false
或super.onInterceptTouchEvent
表示不拦截该事件,继续分发给子视图。
消费
消费对应onTouchEvent()
方法。
该方法返回true
表示处理该事件,不传递该事件给父视图;返回false
表示当前视图不处理该事件,传递该事件给父视图的onTouchEvent()
方法尝试消费。
其他说明
- 如果同时有
Activity
、ViewGroup
、View
时,嵌套层次由外向内是Activity
、ViewGroup
、View
。 View
控件的事件触发顺序是先执行onTouch()
方法,再执行onClick()
方法。如果onTouch()
方法中返回true
,最后不会调用onClick()
方法。- 事件的类型有三种:
ACTION_DOWN
:手指按下操作,表示触摸事件的开始。ACTION_MOVE
:手指移动距离超过阈值会被计为一次ACTION_MOVE
,所以一次完整的触摸事件可能包含多个ACTION_MOVE
,也可能一个都没有。ACTION_UP
:手指离开屏幕,表示触摸事件的结束。
- 如果一层级的最外层控件的
dispatchTouchEvent()
方法返回false
,该层级会不响应触摸事件并且事件也不会被消费,会继续让该层级后面的下一层级处理,相当于点击“穿透”了。
验证触摸事件传递过程
默认的传递过程
代码
1.Test_Touch\app\src\main\java\io\weichao\test_touch\MainActivity.java
1 |
|
2.Test_Touch\app\src\main\res\layout\activity_main.xml
1 |
|
3.Test_Touch\app\src\main\java\io\weichao\test_touch\CustomRelativeLayout.java
1 |
|
4.Test_Touch\app\src\main\java\io\weichao\test_touch\CustomButton.java
1 |
|
显示的界面
点击下面的紫色区域,显示 log
按下会触发1次,弹起会触发1次,每判定出一次移动会触发1次。
点击红色区域,显示 log
中间部分每判定出一次移动会触发1次,这里触发了3次。
点击灰色区域,显示 log
中间部分每判定出一次移动会触发1次,这里触发了3次。
只修改 Activity
只修改 dispatchTouchEvent()方法,返回 true 或 false
点击下面的紫色区域,显示 log
点击红色区域,显示 log
点击灰色区域,显示 log
与默认的传递过程对比
事件被MainActivity
分发过,不管是否被消费,都不会再分发,所以不执行任何onTouchEvent()
方法。
只修改 onTouchEvent()方法,返回 true 或 false
点击下面的紫色区域,显示 log
点击红色区域,显示 log
点击灰色区域,显示 log
与默认的传递过程对比
无变化,但是返回true
时最后不会调用MainAcitivity
的onClick()
方法。
只修改 CustomRelativeLayout
只修改 dispatchTouchEvent()方法,返回 true
点击下面的紫色区域,显示 log
点击红色区域,显示 log
点击灰色区域,显示 log
与默认的传递过程对比
事件被CustomRelativeLayout
分发过,且被消费了,所以不执行任何onTouchEvent()
方法。
只修改 dispatchTouchEvent()方法,返回 false
点击下面的紫色区域,显示 log
点击红色区域,显示 log
点击灰色区域,显示 log
与默认的传递过程对比
事件被CustomRelativeLayout
分发过,但未被消费过,所以该事件被MainActivity
消费掉,执行MainActivity
的onTouchEvent()
方法。
只修改 onInterceptTouchEvent()方法,返回 true
点击下面的紫色区域,显示 log
点击红色区域,显示 log
点击灰色区域,显示 log
与默认的传递过程对比
CustomRelativeLayout
拦截向下传递,所以执行CustomRelativeLayout
和MainActivity
的onTouchEvent()
方法。
只修改 onInterceptTouchEvent()方法,返回 false
点击下面的紫色区域,显示 log
点击红色区域,显示 log
点击灰色区域,显示 log
与默认的传递过程对比
CustomRelativeLayout
不拦截向下传递,所以当CustomButton
有触摸事件时,会消费掉该事件,所以执行CustomButton
的onTouchEvent()
方法;否则,CustomRelativeLayout
不会消费掉该事件,所以执行CustomRelativeLayout
和MainActivity
的onTouchEvent()
方法。
只修改 onTouchEvent()方法,返回 true
点击下面的紫色区域,显示 log
点击红色区域,显示 log
点击灰色区域,显示 log
与默认的传递过程对比
CustomRelativeLayout
不拦截向下传递,所以当CustomButton
有触摸事件时,会消费掉该事件,所以执行CustomButton
的onTouchEvent()
方法;否则,CustomRelativeLayout
会消费掉该事件,所以执行CustomRelativeLayout
的onTouchEvent()
方法。
只修改 onTouchEvent()方法,返回 false
点击下面的紫色区域,显示 log
点击红色区域,显示 log
点击灰色区域,显示 log
与默认的传递过程对比
和【只修改 onInterceptTouchEvent()方法,返回 false】一样。
只修改 CustomButton
只修改 dispatchTouchEvent()方法,返回 true
点击下面的紫色区域,显示 log
点击红色区域,显示 log
点击灰色区域,显示 log
与默认的传递过程对比
CustomRelativeLayout
不拦截向下传递,所以当CustomButton
有触摸事件时,会试图消费掉该事件,但因为CustomButton
已分发过,所以不执行CustomButton
的onTouchEvent()
方法,同时该事件也被消费了,所以不会再被CustomRelativeLayout
或MainActivity
消费;否则,默认CustomRelativeLayout
也不会消费掉该事件,所以执行CustomRelativeLayout
和MainActivity
的onTouchEvent()
方法。
只修改 dispatchTouchEvent()方法,返回 false
点击下面的紫色区域,显示 log
点击红色区域,显示 log
点击灰色区域,显示 log
与默认的传递过程对比
CustomRelativeLayout
不拦截向下传递,所以当CustomButton
有触摸事件时,会试图消费掉该事件,但因为CustomButton
已分发过,所以不执行CustomButton
的onTouchEvent()
方法,但同时未消费过,但默认CustomRelativeLayout
也不会消费掉该事件,所以执行CustomRelativeLayout
和MainActivity
的onTouchEvent()
方法;否则,默认CustomRelativeLayout
也不会消费掉该事件,所以执行CustomRelativeLayout
和MainActivity
的onTouchEvent()
方法。
只修改 onTouchEvent()方法,返回 true
点击下面的紫色区域,显示 log
点击红色区域,显示 log
点击灰色区域,显示 log
与默认的传递过程对比
CustomRelativeLayout
不拦截向下传递,所以当CustomButton
有触摸事件时,会消费掉该事件;否则,默认CustomRelativeLayout
也不会消费掉该事件,所以执行CustomRelativeLayout
和MainActivity
的onTouchEvent()
方法。
只修改 onTouchEvent()方法,返回 false
点击下面的紫色区域,显示 log
点击红色区域,显示 log
点击灰色区域,显示 log
与默认的传递过程对比
完全一样。