View的事件分发机制
程序员文章站
2022-05-14 15:26:51
...
事件分发:即对MotionEvent事件的分发过程,当产生一个MotionEvent之后,系统需要把它传递到一个具体的View的过程。
相关方法
dispatchTouchEvent方法:用来进行事件的分发,如果事件传递到当前的View,此方法被调用
返回结果:代表是否消费该事件
受当前View的onTouchEvent和下级View的dispatchTouchEvent方法的影响onInterceptTouchEvent方法:在dispatchTouchEvent中调用,用来判断是否拦截事件,如果当前View拦截了某个时间,则在统一序列事件当中,此方法不会再被调用
返回结果表示是否拦截当前事件onTouchEvent方法:在dispatchTouchEvent方法中调用,用来处理点击事件,如果不消费当前事件,则当前VIew无法再次接收到事件。
返回结果:表示是否消费当前View。
以下是在网上看到的一张事件分发图(谢谢出处):
设置监听
- 如果设置OnTouchListener,那么onTouch会被调用
onTouch返回false,则onTouchEvent会被调用;
返回true,则onTouchEvent不会调用。 - 在onTouchEvent中,如果设置了OnClickListener,则onClick会被调用
事件大方面的传递: Activity->Window->View ,如果都没有处理,最终交由Activity处理。
结论(根据《Android开发艺术塔索》做的笔记)
- 同一事件序列是指从手指接触屏幕那一刻起,到手指离开屏幕那一刻结束:DOWN->MOVE->MOVE->…->UP
- 正常情况下,一个事件序列只能够被一个View拦截且消耗
- 某个View一旦决定拦截,那么这一事件序列都只能由它来处理,并且它的onInterceptTouchEvent不会再被调用
- 某个View一旦开始处理事件,如果它不消耗ACTION_DOWN事件(在onTouchEvent返回false),那么同一事件序列的其他事件将不会再交给它处理,而是给它的父View处理,即父View的OnTouchEvent会被调用
- 如果View不消耗除ACTION_DOWN事件,那么这个点击事件会被消失,最终这些消失的事件会传给Activity处理
- ViewGroup默认不拦截任何事件,查看源码可知它的onInterceptTouchEvent默认返回false
- View没有onInterceptTouchEvent方法,一旦事件传递给它,它的onTouchEvent会被调用
- View的onTouchEvent方法默认是消耗事件的,即返回true,除非它是不可点击的(clickable&longClickable=false)
- View的enable属性不影响onTouchEvent默认返回的值,只要该View的clickable/longClickable=true,那么它的onTouchEvent就返回true
- onClick会发生的前提是View是可点击的,并且收到DOWN和UP的事件
-
事件传递:
从外到内
从父到子
子View可以通过requestDisallowInterceptTouchEvent方法可以干预父元素的事件分发过程,ACTION_DOWN除外以上是个人对View事件分发机制的学习的笔记,如有错误,请多多指出。