- View 的事件分发机制 ==
如果点击一个 ViewGroup 的话,点击事件产生之后:
-
1.1 首先会传递给这个 ViewGroup 。
-
1.2 然后调用该 ViewGroup 的
dispatchTouchEvent
分发事件。 -
1.3.1 如果 ViewGroup 的
onInterceptTouchEvent
返回 true,则表示 拦截事件。接着会将该事件交给该 ViewGroup 处理,调用其onTouchEvent
。 -
1.3.2 如果 ViewGroup 的
onInterceptTouchEvent
返回 false,则表示 不拦截事件。这个事件就会交给 ViewGroup 的 子 View 去处理。接着 在 子 View 中 继续循环 1.1、1.2、1.3.1、1.3.2。
一个 View 需要处理事件的时候,如果设置了 onTouchListener。那么,接着这个 onTouchListener 的 onTouch
方法会别调用。
- 2.1 如果
onTouch
返回 true。那么onTouchEvent
会被调用。 - 2.1.1 在
onTouchEvent
中,如果设置了 onClickListener。会调用performClick()
,接着就回调了OnClickListener.onClick(View v)
。
所以:
onTouchListener > onTouchEvent > onClickListener
一个点击事件触发后,会有如下的传递过程:Activity >> Window >> View(从上到下)。
如果,中间没有拦截,传到最底下的 View 时,会从 最底下的 View 开始 调用 onTouchEvent
方法,如果一直返回 false 的话,就调用 父 View 的 onTouchEvent
方法 ,直到 Activity 为止。所以,如果 onTouchEvent
一直返回 false 的过程是:最底层 View.onTouchEvent >> 倒数第二层 View.onTouchEvent >> Activity.onTouchEvent(从下到上)
-
1. 同一个序列的事件:手机按下屏幕到离开屏幕的过程。这个过程以 down 事件开始,然后到 N 次 的 move 事件,最后以 up 事件结束。
-
2. 正常情况下,一个事件序列只能被一个 View 拦截并且消费。
-
3. 一个 View 拦截了事件后,这一序列的事件都会交给该 View 执行处理。因此,同一个序列事件不能分别交给两个 View 同时处理。但是有特殊手段能做到,比如:在一个 View 的 onTouchEvent 内交给其他 View 处理。
-
4. 在同一序列事件的情况下,如果 View 拦截了事件,那么后续的事件都由该 View 去处理,并且不会再该序列事件中调用 onInterceptTouchEvent。
-
5. 如果 View 不消费 DOWN 以外的事件,这个事件消失。父元素的 onTouchEvent 也不会调用。并且当前 View 可以持续收到后续事件,那么之前消失的事件会传递到 Activity 中进行处理。
-
6. ViewGroup 默认不拦截事件,源码中 ViewGroup 的 onInterceptTouchEvent 方法默认返回 false。
-
7. View 没有 onInterceptTouchEvent 方法,如果有事件传递给它,那么它的 onTouchEvent 方法会被调用。
-
8. View 的 onTouchEvent 事件默认会被消费。除非它被设置为不可点击状态(
clickable or longClickable == false
)。 -
9. View 的
enable
属性不会影响 onTouchEvent 方法的返回值。只要clickable or longClickable == true
,那么 onTouchEvent 方法 就会返回 true。 -
10.
onClick
发生的前提是当前 View 是可点击的。并且接收到了 DOWN 事件。 -
11. 事件的传递过程是 由外向内 的。事件会从 Activity >> Window >> View 传递给父元素,然后一直传递给子元素。在子元素中可以通过
requestDisallowInterceptTouchEvent
方法干预父元素的分发。但 DOWN 事件除外。