一、外部传递到ViewGroup中
Activity会通过 getWindow( ) 获取PhoneWindow对象并调用它的superDispatchTouchEvent( ),该方法会调用它(PhoneWindow)的内部类 DecorView 的 superDispatchTouchEvent( ),而它(DecorView)继承自FrameLayout,因此 DecorView 是一个顶级的 ViewGroup,这就实现了事件从外部到 ViewGroup 的传递。
二、ViewGroup中传递
一个事件序列:ACTION_DOWN+0或N个ACTION_MOVE+ACTION_UP。
ACTION_DOWN | 手指接触到屏幕产生。 |
ACTION_MOVE | 手指在屏幕上移动产生。 |
ACTION_UP | 手指离开屏幕产生。 |
2.1 ACTION_DOWN事件
返回值\函数 | dispatchTouchEvent( ) 事件分发 | onTouchEvent( ) 事件处理 |
true | 一旦返回 true 事件就停止传递了,即该事件在此被消费了。 | |
false | 返回false会将事件回传给父控件的onTouchEvent( )处理。 | |
停止向下传递并往父控件回溯。 | 不消费事件继续向上传递。 | |
super | ViewGroup:会调用onInterceptTouchEvent( )来控制事件。返回super/false会继续向下传递给子控件(默认不拦截,因为子控件也需要该事件)。返回true会拦截事件给自己的onTouchEvent( )处理。 | |
View:没有子控件因此没有事件拦截方法,默认实现就是来调用自己的onTouchEvent( )。 | ||
如果没有重写,默认情况下dispatchTouchEvent( )到onTouchEvent( )连起来整个流程呈一个U型。 |
2.2、ACTION_MOVE、ACTION_UP事件
ACTION_DOWN在哪个控件中消费,ACTION_MOVE 和 ACTION_UP 通过 dispatchTouchEvent( ) 就只传递到该控件为止,不会继续往下传递。ACTION_DOWN 如果是在 dispatchTouchEvent( ) 中消费的,那么就到此为止,如果是在 onTouchEvent( ) 中消费的,那么会传递过去。
三、自定义控件
3.1 事件传递
编写自定义ViewGroup的时候不要直接拦截所有事件,ACTION_DOWN一定要传递到最底层(若 ViewGroup 要拦截事件,在 dispatchTouchEvent( ) 中判断如果事件==ACTION_DOWN不拦截),否则拦得太死传递不下去,子控件没办法申请父控件不要拦截。
没有处理事件,DOWN以外其它事件则不会传递进来(只针对控件不针对Activity)。
3.2 事件拦截
如果ViewGroup要拦截事件,拦截逻辑写在onInterceptTouchEvent(),处理效果写在onTouchEvent()。
3.3 子控件请求父控件不要拦截
复写dispatchTouchEvent()写入一行getParent().resquestDisallowInterceptTouchEvent(true);