基本概念
事件类型
主要有如下三种: 
| 12
 3
 
 | - MotionEvent.ACTION_DOWN   - MotionEvent.ACTION_MOVE
 - MotionEvent.ACTION_UP
 
 | 
事件处理 API
| 12
 3
 4
 5
 6
 
 | - Activity.dispatchTouchEvent()    - Activity.onTouchEvent()
 - ViewGroup.dispatchTouchEvent()
 - ViewGroup.onInterceptTouchEvent()
 - View.dispatchTouchEvent()
 - View.onTouchEvent()
 
 | 
主要是描述 Touch 事件的分发,拦载,响应三者的关系。 Touch 事件发生时,会由根元素逐级分发直到最内层 View,然后反过来逐级响应该事件。  
名词解释
分发:该方法封装了事件分发的整个过程,是事件分发的调度者和指挥官。
拦载:该方法表示是否拦截事件,只有 ViewGroup 有该回调。
返回 true 表示拦截,返回 false 或者 super.onInterceptTouchEvent  表示不拦截  
响应:该方法表示响应并处理事件  
消费:表示事件不再继续逐级向下传递分发,或者不再继续逐级向上响应。也就是事件在某个方法中被消费后,该方法就是整个分发、拦载、响应流程的终点。  
处理顺序
分发顺序为逐级向下:
dispatchTouchEvent:  Activity(Window) -> ViewGroup -> View
响应顺序为逐级向上:
onTouchEvent:  View -> ViewGroup --> Activity  
事件分发流程
DOWN 事件 U 型流程图
流程图是针对 ACTION_DOWN 事件的分析,而 ACTION_MOVE/ACTION_UP 和事件的消费有关,放到后面分析。
事件的正常流程是:由上向下分发,并由下向上响应的一个 U 型图。箭头上的值表示返回值,其中 super 表示返回父类实现。   

流程图总结
- 所有 API返回值都为super,表示事件能走完整个U型流程。
- 分发和响应只要返回值为 true都表示消费该事件,流程不再继续流转。
- Activity中的分发和响应
分发:只有返回 super 才能逐级向下分发,true/false 都表示事件最终被消费。
响应:不管返回什么值,都表示事件被最终消费。  
- ViewGroup和- View的分发和响应返回- false,都表示流转到上一级执行- onTouchEvent(响应)。
- 拦载
 返回true表示拦载,事件不会继续分发, 当前ViewGroup直接响应事件,U型流程继续向前走。
 返回false或者super表示不拦载,事件继续向下分发。
MOVE 和 UP 事件流程
ACTION_MOVE/ACTION_UP 和  ACTION_DOWN 事件的消费有关。在 U 型图中,ACTION_DOWN 事件在哪一层被消费,ACTION_MOVE/ACTION_UP 就只能到达这一层。  
- 分发
 如果DOWN事件被分发消费,UP事件只能逐级向下分发到这一层。
- 响应
 如果DOWN事件被响应后消费,UP事件逐级向下分发到这一层,并在这一层响应后直接被消费。
示例 1
View 分发时消费 DOWN 事件。
View 在 dispatchTouchEvent 中消费 DOWN 事件, MVOE/UP 也只能分发到 CustomView 这一层。  

示例 2
ViewGroup 响应时消费 DOWN 事件。
ViewGroup 在 onTouchEvent 中消费 DOWN 事件, MOVE/UP 只能分发到这一层,并在这一层响应后直接消费。  

示例 Log 分析
示例结构图
CustomView :为自定义 View
CustomLayout :为自定义 ViewGroup
CustomLayout2 :继承 LinearLayout  

示例完整布局文件:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 
 | <?xml version="1.0" encoding="utf-8"?><android.support.constraint.ConstraintLayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:app="http://schemas.android.com/apk/res-auto"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 tools:context="com.***.view.ViewEvent">
 
 <com.***.view.CustomLayout
 android:id="@+id/view_event_custom_layout"
 android:layout_width="300dp"
 android:layout_height="300dp"
 app:layout_constraintLeft_toLeftOf="parent"
 app:layout_constraintRight_toRightOf="parent"
 android:layout_marginLeft="8dp"
 android:layout_marginRight="8dp"
 app:layout_constraintTop_toTopOf="parent"
 android:layout_marginTop="8dp"
 app:custom_orientation="vertical">
 
 <com.***.view.CustomLayout2
 android:id="@+id/view_event_custom_layout_2"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 app:custom_orientation="horizontal">
 <com.***.view.CustomView
 android:id="@+id/view_event_custom_view_button"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 app:custom_text="@string/view_event_custom_view_button"
 app:custom_color="@color/colorAccent"
 app:custom_size="@dimen/smallTextSize"
 android:layout_marginLeft="@dimen/custom_margin_view"/>
 
 <TextView
 android:id="@+id/view_event_textview"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="@string/view_event_textview"
 android:layout_marginLeft="@dimen/custom_margin_text"/>
 </com.***.view.CustomLayout2>
 
 <TextView
 android:id="@+id/view_event_textview_2"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="@string/view_event_textview"
 app:custom_margin="@dimen/custom_margin_text"/>
 
 </com.***.view.CustomLayout>
 
 </android.support.constraint.ConstraintLayout>
 
 | 
正常流程,不做任何处理
所有 API 都返回的是 super.***,走完整个 U 型图的流程。如下示例为点击 CustomView 后,触发了事件逐级向下分发、拦载、逐级向上响应的完整流程,包含 ACTION_DOWN 和 ACTION_UP 事件。  
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 
 | // 处理 ACTION_DOWN 事件,Activity 开始分发事件19:26: 26395/com.yD/:ViewEventActivity:: dispatchTouchEvent: ev MotionEvent { action=ACTION_DOWN...}
 // 第一层 ViewGroup 接收事件并向下分发
 19:26: 26395/com.yD/:CustomLayout:: dispatchTouchEvent:
 // 第一层 ViewGroup 判断是否拦载
 19:26: 26395/com.yD/:CustomLayout:: onInterceptTouchEvent:
 // 第二层 ViewGroup 接收事件并向下分发
 19:26: 26395/com.yD/:CustomLayout2:: :XMT:CustomLayout2:, dispatchTouchEvent:
 // 第二层 ViewGroup 判断是否拦载
 19:26: 26395/com.yD/:CustomLayout2:: :XMT:CustomLayout2:, onInterceptTouchEvent:
 // 第三层 View 接收事件并分发
 19:26: 26395/com.yD/:CustomView:: dispatchTouchEvent:
 // 第三层 View 响应事件
 19:26: 26395/com.yD/:CustomView:: onTouchEvent:
 // 第二层 ViewGroup 向上响应事件
 19:26: 26395/com.yD/:CustomLayout2:: :XMT:CustomLayout2:, onTouchEvent:
 // 第一层 ViewGroup 向上响应事件
 19:26: 26395/com.yD/:CustomLayout:: onTouchEvent:
 // Activity 开始响应事件并消费
 19:26: 26395/com.yD/:ViewEventActivity:: onTouchEvent:
 // 点击结束抬手,ACTION_UP,Activity 开始分发事件
 19:26: 26395/com.yD/:ViewEventActivity:: dispatchTouchEvent: ev MotionEvent { action=ACTION_UP...}
 // 因为是 Activity 消费了 DOWN 事件,所以 UP 事件只到这一层响应并消费
 19:26: 26395/com.yD/:ViewEventActivity:: onTouchEvent:
 
 | 
dispatchTouchEvent 的返回值
- 当层返回 super.dispatchTouchEvent
 不影响事件分发和响应,和正常流程完全一样
- 当层返回 false
分发:表示事件不再逐级向下传递分发。
响应:同时该层也不会响应事件,该层(不含)逐级向上所有层都响应事件。
如下示例为在 CustomLayout2 层直接返回 false:      
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | // 处理 ACTION_DOWN 事件19:40: 6728/com.yD/:ViewEventActivity:: dispatchTouchEvent: ev MotionEvent { action=ACTION_DOWN...}
 19:40: 6728/com.yD/:CustomLayout:: dispatchTouchEvent:
 19:40: 6728/com.yD/:CustomLayout:: onInterceptTouchEvent:
 // CustomLayout2 层直接返回 false ,事件不再向下分发传递,同时本层也不响应事件
 19:40: 6728/com.yD/:CustomLayout2:: :XMT:CustomLayout2:, dispatchTouchEvent:
 // 该层(不含)逐级向上所有层都响应事件
 19:40: 6728/com.yD/:CustomLayout:: onTouchEvent:
 19:40: 6728/com.yD/:ViewEventActivity:: onTouchEvent:
 // 处理 ACTION_UP 事件,Activity 消费了 DOWN 事件,所以 UP 事件只到这一层响应并消费
 19:40: 6728/com.yD/:ViewEventActivity:: dispatchTouchEvent: ev MotionEvent { action=ACTION_UP...}
 19:40: 6728/com.yD/:ViewEventActivity:: onTouchEvent:
 
 | 
分发:事件不会继续在整个流程中传递分发
响应:所有层都不响应该事件(因为分发流程未走完,所以响应流程无法开始)
如下示例为在最底层的 CustomView 中直接返回 true   
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | // 处理 ACTION_DOWN 事件19:46: 11801/com.yD/:XMT:ViewEventActivity:: dispatchTouchEvent: ev MotionEvent { action=ACTION_DOWN...}
 19:46: 11801/com.yD/:XMT:CustomLayout:: dispatchTouchEvent:
 19:46: 11801/com.yD/:XMT:CustomLayout:: onInterceptTouchEvent:
 19:46: 11801/com.yD/:XMT:CustomLayout2:: :XMT:CustomLayout2:, dispatchTouchEvent:
 19:46: 11801/com.yD/:XMT:CustomLayout2:: :XMT:CustomLayout2:, onInterceptTouchEvent:
 // CustomView 层直接返回 true,事件不再继续分发,同时所有层都不会响应事件
 19:46: 11801/com.yD/:XMT:CustomView:: dispatchTouchEvent:
 // 处理 ACTION_UP 事件,CustomView 的dispatchTouchEvent 消费了 DOWN 事件
 19:46: 11801/com.yD/:XMT:ViewEventActivity:: dispatchTouchEvent: ev MotionEvent { action=ACTION_UP...}
 19:46: 11801/com.yD/:XMT:CustomLayout:: dispatchTouchEvent:
 19:46: 11801/com.yD/:XMT:CustomLayout:: onInterceptTouchEvent:
 19:46: 11801/com.yD/:XMT:CustomLayout2:: :XMT:CustomLayout2:, dispatchTouchEvent:
 19:46: 11801/com.yD/:XMT:CustomLayout2:: :XMT:CustomLayout2:, onInterceptTouchEvent:
 // ACTION_UP 传递分发到这一层的 dispatchTouchEvent 并消费
 19:46: 11801/com.yD/:XMT:CustomView:: dispatchTouchEvent:
 
 | 
onInterceptTouchEvent 的返回值
无法消费事件。  
分发:事件不再逐级向下传递。
响应:该层(含)逐级向上所有层都响应事件。
如下示例为在 CustomLayout2 中直接返回 true    
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | // 处理 ACTION_DOWN 事件19:57: 22163/com.yD/:XMT:ViewEventActivity:: dispatchTouchEvent: ev MotionEvent { action=ACTION_DOWN...}
 19:57: 22163/com.yD/:XMT:CustomLayout:: dispatchTouchEvent:
 19:57: 22163/com.yD/:XMT:CustomLayout:: onInterceptTouchEvent:
 19:57: 22163/com.yD/:XMT:CustomLayout2:: :XMT:CustomLayout2:, dispatchTouchEvent:
 // CustomLayout2 层直接返回true,拦载该事件,事件不再继续向下分发
 19:57: 22163/com.yD/:XMT:CustomLayout2:: :XMT:CustomLayout2:, onInterceptTouchEvent:
 // 从 CustomLayout2 层(含)开始逐级向上响应事件
 19:57: 22163/com.yD/:XMT:CustomLayout2:: :XMT:CustomLayout2:, onTouchEvent:
 19:57: 22163/com.yD/:XMT:CustomLayout:: onTouchEvent:
 19:57: 22163/com.yD/:XMT:ViewEventActivity:: onTouchEvent:
 // 处理 ACTION_UP 事件,Activity 消费了 DOWN 事件,所以 UP 事件只到这一层响应并消费
 19:57: 22163/com.yD/:XMT:ViewEventActivity:: dispatchTouchEvent: ev MotionEvent { action=ACTION_UP...}
 19:57: 22163/com.yD/:XMT:ViewEventActivity:: onTouchEvent:
 
 | 
onTouchEvent 返回值
分发:返回值不影响事件传递分发。
响应:决定该层(不含)逐级向上所有层是否响应事件。     
- 当层返回 - false或者- super.onTouchEvent
 表示不影响事件分发和响应,和正常流程完全一样。如果直接返回- false仅仅是比- super.onTouchEvent少调用一次父类的- onTouchEvent。
 
- 当层返回 - true
 表示该层消费了事件,即该层(不含)逐级向上所有层都不响应事件了。
 该层(含)及之下层已经响应了事件。
 如下示例为- CustomLayout2中返回- true:
 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | // 处理 ACTION_DOWN 事件20:01: 25724/com.yD/:XMT:ViewEventActivity:: dispatchTouchEvent: ev MotionEvent { action=ACTION_DOWN...}
 20:01: 25724/com.yD/:XMT:CustomLayout:: dispatchTouchEvent:
 20:01: 25724/com.yD/:XMT:CustomLayout:: onInterceptTouchEvent:
 20:01: 25724/com.yD/:XMT:CustomLayout2:: :XMT:CustomLayout2:, dispatchTouchEvent:
 20:01: 25724/com.yD/:XMT:CustomLayout2:: :XMT:CustomLayout2:, onInterceptTouchEvent:
 20:01: 25724/com.yD/:XMT:CustomView:: dispatchTouchEvent:
 // 并不影响事件的分发,也不影响下层级的响应
 20:01: 25724/com.yD/:XMT:CustomView:: onTouchEvent:
 // CustomLayout2 中返回 true,该层(不含)逐级向上将不再响应事件
 20:01: 25724/com.yD/:XMT:CustomLayout2:: :XMT:CustomLayout2:, onTouchEvent:
 // 处理 ACTION_UP 事件,CustomLayout2 的 onTouchEvent 响应并消费了事件
 20:01: 25724/com.yD/:XMT:ViewEventActivity:: dispatchTouchEvent: ev MotionEvent { action=ACTION_UP...}
 20:01: 25724/com.yD/:XMT:CustomLayout:: dispatchTouchEvent:
 20:01: 25724/com.yD/:XMT:CustomLayout:: onInterceptTouchEvent:
 20:01: 25724/com.yD/:XMT:CustomLayout2:: :XMT:CustomLayout2:, dispatchTouchEvent:
 // ACTION_UP 传递分发到这一层,onTouchEvent 响应并消费
 20:01: 25724/com.yD/:XMT:CustomLayout2:: :XMT:CustomLayout2:, onTouchEvent:
 
 | 
CustomLayout2 继承 CustomLayout
如果 CustomLayout2 继承 CustomLayout ,则在调用 supder.*** 会多执行一次 CustomLayout 相关方法。     
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 
 | // 事件正常下发10:01: 12487/com.yD/:ViewEventActivity:: dispatchTouchEvent: ev MotionEvent { action=ACTION_DOWN...}
 10:01: 12487/com.yD/:CustomLayout:: dispatchTouchEvent:
 10:01: 12487/com.yD/:CustomLayout:: onInterceptTouchEvent:
 10:01: 12487/com.yD/:CustomLayout2:: :XMT:CustomLayout2:, dispatchTouchEvent:
 // 调用 super.***
 10:01: 12487/com.yD/:CustomLayout:: dispatchTouchEvent:
 10:01: 12487/com.yD/:CustomLayout2:: :XMT:CustomLayout2:, onInterceptTouchEvent:
 // 调用 super.***
 10:01: 12487/com.yD/:CustomLayout:: onInterceptTouchEvent:
 10:01: 12487/com.yD/:CustomView:: dispatchTouchEvent:
 10:01: 12487/com.yD/:CustomView:: onTouchEvent:
 10:01: 12487/com.yD/:CustomLayout2:: :XMT:CustomLayout2:, onTouchEvent:
 // 调用 super.***
 10:01: 12487/com.yD/:CustomLayout:: onTouchEvent:
 10:01: 12487/com.yD/:CustomLayout:: onTouchEvent:
 10:01: 12487/com.yD/:ViewEventActivity:: onTouchEvent:
 10:01: 12487/com.yD/:ViewEventActivity:: dispatchTouchEvent: ev MotionEvent { action=ACTION_UP...}
 10:01: 12487/com.yD/:ViewEventActivity:: onTouchEvent:
 
 | 
- CustomLayout的- onTouchEvent返回- true时
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 
 | // 事件正常下发10:10: 19035/com.yD/:ViewEventActivity:: dispatchTouchEvent: ev MotionEvent { action=ACTION_DOWN...}
 10:10: 19035/com.yD/:CustomLayout:: dispatchTouchEvent:
 10:10: 19035/com.yD/:CustomLayout:: onInterceptTouchEvent:
 10:10: 19035/com.yD/:CustomLayout2:: :XMT:CustomLayout2:, dispatchTouchEvent:
 // 调用 super.***
 10:10: 19035/com.yD/:CustomLayout:: dispatchTouchEvent:
 10:10: 19035/com.yD/:CustomLayout2:: :XMT:CustomLayout2:, onInterceptTouchEvent:
 // 调用 super.***
 10:10: 19035/com.yD/:CustomLayout:: onInterceptTouchEvent:
 10:10: 19035/com.yD/:CustomView:: dispatchTouchEvent:
 10:10: 19035/com.yD/:CustomView:: onTouchEvent:
 10:10: 19035/com.yD/:CustomLayout2:: :XMT:CustomLayout2:, onTouchEvent:
 // 调用 super.***,但是 CustomLayout 在 onTouchEvent 响应完后消费了该事件
 10:10: 19035/com.yD/:CustomLayout:: onTouchEvent:
 // 所以不再再次调用 CustomLayout:: onTouchEvent:
 // UP 事件正常下发
 10:10: 19035/com.yD/:ViewEventActivity:: dispatchTouchEvent: ev MotionEvent { action=ACTION_UP...}
 10:10: 19035/com.yD/:CustomLayout:: dispatchTouchEvent:
 10:10: 19035/com.yD/:CustomLayout:: onInterceptTouchEvent:
 10:10: 19035/com.yD/:CustomLayout2:: :XMT:CustomLayout2:, dispatchTouchEvent:
 10:10: 19035/com.yD/:CustomLayout:: dispatchTouchEvent:
 10:10: 19035/com.yD/:CustomLayout2:: :XMT:CustomLayout2:, onTouchEvent:
 // 同理调用 super.*** 时 CustomLayout 在 onTouchEvent 响应完后消费了该事件
 10:10: 19035/com.yD/:CustomLayout:: onTouchEvent:
 
 | 
事件分发及响应的部分源码分析
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | public boolean dispatchTouchEvent(MotionEvent ev) {if (ev.getAction() == MotionEvent.ACTION_DOWN) {
 onUserInteraction();
 }
 if (getWindow().superDispatchTouchEvent(ev)) {
 return true;
 }
 return onTouchEvent(ev);
 }
 
 | 
大体的分发过程为:首先传递到 Activity,然后传给了 Activity 依附的 Window,接着由 Window 传给视图的顶层 View 也就是 DecorView,最后由 DecorView 向整个 ViewTree 分发。
在 getWindow().superDispathTouchEvent 就是用来分发事件到 DecorView 中。如果整个 ViewTree 分发没有消费事件,会调用 Activity 的 onTouchEvent。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 
 | public boolean dispatchTouchEvent(MotionEvent e) {
 
 boolean consumed = false;
 if (onInterceptTouchEvent(e)) {
 
 
 
 consumed = onTouchEvent(e);
 } else {
 
 
 
 for (View view: children) {
 consumed = view.dispatchTouchEvent(e);
 if (consumed) {
 break;
 }
 }
 
 if (!consumed) {
 consumed = onTouchEvent(e);
 }
 }
 return consumed;
 }
 
 | 
常见监听事件的消费
onTouch 监听
| 12
 3
 4
 5
 6
 
 | view.setOnTouchListener(new View.OnTouchListener(){@Override
 public boolean onTouch(View v, MotionEvent event) {
 ...
 }
 }
 
 | 
- onTouch返回值
 返回- false表示不影响整个事件分发响应流程。
 返回- true表示- dispatchTouchEvent分发消费这次事件。
 对应的- Log打印:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 
 | // CustomView 监听 onTouch 事件后的分发流程// onTouch 返回 false 走完整个 U 型流程
 17:07: 29706/com.yD/:ViewEventActivity:: dispatchTouchEvent: ev MotionEvent { action=ACTION_DOWN...}
 17:07: 29706/com.yD/:CustomLayout:: dispatchTouchEvent:
 17:07: 29706/com.yD/:CustomLayout:: onInterceptTouchEvent:
 17:07: 29706/com.yD/:CustomLayout2:: :XMT:CustomLayout2:, dispatchTouchEvent:
 17:07: 29706/com.yD/:CustomLayout2:: :XMT:CustomLayout2:, onInterceptTouchEvent:
 17:07: 29706/com.yD/:CustomView:: dispatchTouchEvent:
 17:07: 29706/com.yD/:ViewEventActivity:: customView, onTouch:
 17:07: 29706/com.yD/:CustomView:: onTouchEvent:
 17:07: 29706/com.yD/:CustomLayout2:: :XMT:CustomLayout2:, onTouchEvent:
 17:07: 29706/com.yD/:CustomLayout:: onTouchEvent:
 17:07: 29706/com.yD/:ViewEventActivity:: onTouchEvent:
 17:07: 29706/com.yD/:ViewEventActivity:: dispatchTouchEvent: ev MotionEvent { action=ACTION_UP...}
 17:07: 29706/com.yD/:ViewEventActivity:: onTouchEvent:
 
 
 // CustomView 监听 onTouch 事件后的分发流程
 // onTouch 返回 true
 // 查看源码 onTouch 是在 View 的 dispatchTouchEvent 中调用的
 // 返回 true 表示 消费了该事件
 17:09: 31152/com.yD/:ViewEventActivity:: dispatchTouchEvent: ev MotionEvent { action=ACTION_DOWN...}
 17:09: 31152/com.yD/:CustomLayout:: dispatchTouchEvent:
 17:09: 31152/com.yD/:CustomLayout:: onInterceptTouchEvent:
 17:09: 31152/com.yD/:CustomLayout2:: :XMT:CustomLayout2:, dispatchTouchEvent:
 17:09: 31152/com.yD/:CustomLayout2:: :XMT:CustomLayout2:, onInterceptTouchEvent:
 17:09: 31152/com.yD/:CustomView:: dispatchTouchEvent:
 17:09: 31152/com.yD/:ViewEventActivity:: customView, onTouch:
 17:09: 31152/com.yD/:ViewEventActivity:: dispatchTouchEvent: ev MotionEvent { action=ACTION_UP...}
 17:09: 31152/com.yD/:CustomLayout:: dispatchTouchEvent:
 17:09: 31152/com.yD/:CustomLayout:: onInterceptTouchEvent:
 17:09: 31152/com.yD/:CustomLayout2:: :XMT:CustomLayout2:, dispatchTouchEvent:
 17:09: 31152/com.yD/:CustomLayout2:: :XMT:CustomLayout2:, onInterceptTouchEvent:
 17:09: 31152/com.yD/:CustomView:: dispatchTouchEvent:
 17:09: 31152/com.yD/:ViewEventActivity:: customView, onTouch:
 
 | 
- 源码分析
 源码可以看出,onTouch回调是在dispatchTouchEvent中调用的,所以返回true时,表示分发消费了事件。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | public boolean dispatchTouchEvent(MotionEvent event) {...
 ListenerInfo li = mListenerInfo;
 if (li != null && li.mOnTouchListener != null
 && (mViewFlags & ENABLED_MASK) == ENABLED
 
 && li.mOnTouchListener.onTouch(this, event)) {
 result = true;
 }
 
 
 if (!result && onTouchEvent(event)) {
 result = true;
 }
 ...
 }
 
 | 
onLongClick 监听
| 12
 3
 4
 5
 6
 
 | view.setOnLongClickListener(new View.OnLongClickListener(){@Override
 public boolean onLongClick(View v) {
 ...
 }
 }
 
 | 
- onLongClick返回值
 不管返回- true还是- false,都表示在- onTouchEvent响应中消费该事件,并且是在- ACTION_DOWN中执行- onLongClick回调。分析见下面- onTouchEvent部分源码。对应的- Log打印:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | 17:14: 3237/com.yD/:ViewEventActivity:: dispatchTouchEvent: ev MotionEvent { action=ACTION_DOWN...}17:14: 3237/com.yD/:CustomLayout:: dispatchTouchEvent:
 17:14: 3237/com.yD/:CustomLayout:: onInterceptTouchEvent:
 17:14: 3237/com.yD/:CustomLayout2:: :XMT:CustomLayout2:, dispatchTouchEvent:
 17:14: 3237/com.yD/:CustomLayout2:: :XMT:CustomLayout2:, onInterceptTouchEvent:
 17:14: 3237/com.yD/:CustomView:: dispatchTouchEvent:
 17:14: 3237/com.yD/:CustomView:: onTouchEvent:
 
 17:14: 3237/com.yD/:ViewEventActivity:: customView, onLongClick:
 17:14: 3237/com.yD/:ViewEventActivity:: dispatchTouchEvent: ev MotionEvent { action=ACTION_UP...}
 17:14: 3237/com.yD/:CustomLayout:: dispatchTouchEvent:
 17:14: 3237/com.yD/:CustomLayout:: onInterceptTouchEvent:
 17:14: 3237/com.yD/:CustomLayout2:: :XMT:CustomLayout2:, dispatchTouchEvent:
 17:14: 3237/com.yD/:CustomLayout2:: :XMT:CustomLayout2:, onInterceptTouchEvent:
 17:14: 3237/com.yD/:CustomView:: dispatchTouchEvent:
 17:14: 3237/com.yD/:CustomView:: onTouchEvent:
 
 | 
onClick 监听
| 12
 3
 4
 5
 6
 
 | view.setOnClickListener(new View.OnClickListener(){@Override
 public void onClick(View v) {
 ...
 }
 }
 
 | 
- 事件消费
 在onTouchEvent响应中消费该事件,并且是在ACTION_UP中执行onClick回调。对应的 Log 打印:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | // CustomView 监听 onClick 事件后的分发流程// 相当于在 onTouchEvent 中消费了该事件
 17:03: 26616/com.yD/:ViewEventActivity:: dispatchTouchEvent: ev MotionEvent { action=ACTION_DOWN...}
 17:03: 26616/com.yD/:CustomLayout:: dispatchTouchEvent:
 17:03: 26616/com.yD/:CustomLayout:: onInterceptTouchEvent:
 17:03: 26616/com.yD/:CustomLayout2:: :XMT:CustomLayout2:, dispatchTouchEvent:
 17:03: 26616/com.yD/:CustomLayout2:: :XMT:CustomLayout2:, onInterceptTouchEvent:
 17:03: 26616/com.yD/:CustomView:: dispatchTouchEvent:
 17:03: 26616/com.yD/:CustomView:: onTouchEvent:
 17:03: 26616/com.yD/:ViewEventActivity:: dispatchTouchEvent: ev MotionEvent { action=ACTION_UP...}
 17:03: 26616/com.yD/:CustomLayout:: dispatchTouchEvent:
 17:03: 26616/com.yD/:CustomLayout:: onInterceptTouchEvent:
 17:03: 26616/com.yD/:CustomLayout2:: :XMT:CustomLayout2:, dispatchTouchEvent:
 17:03: 26616/com.yD/:CustomLayout2:: :XMT:CustomLayout2:, onInterceptTouchEvent:
 17:03: 26616/com.yD/:CustomView:: dispatchTouchEvent:
 17:03: 26616/com.yD/:CustomView:: onTouchEvent:
 // ACTION_UP 中响应 onClick 事件
 17:03: 26616/com.yD/:ViewEventActivity:: customView, onClick:
 
 | 
- 源码分析
 参考如下源码,onLongClick和onClick事件都是在onTouchEvent响应中回调了监听,其中:
 onLongClick是在ACTION_DOWN中处理监听回调
 onClick是在ACTION_UP中处理监听回调
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 
 | public boolean onTouchEvent(MotionEvent event) {...
 final int action = event.getAction();
 ...
 if (((viewFlags & CLICKABLE) == CLICKABLE ||
 (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) ||
 (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) {
 switch (action) {
 case MotionEvent.ACTION_UP:
 ...
 if (mPerformClick == null) {
 mPerformClick = new PerformClick();
 }
 if (!post(mPerformClick)) {
 
 performClick();
 }
 ...
 case MotionEvent.ACTION_DOWN:
 ...
 setPressed(true, x, y);
 
 checkForLongClick(0, x, y);
 ...
 }
 return true;
 }
 ...
 }
 
 | 
ViewGroup 中拒绝拦载事件
可以通过设置 FLAG_DISALLOW_INTERCEPT 来要求 ViewGroup 拒绝拦载事件,源码如下:  
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 
 | @Override
 public void requestDisallowInterceptTouchEvent(
 boolean disallowIntercept) {
 
 if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT)
 != 0)) {
 
 return;
 }
 
 if (disallowIntercept) {
 mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
 } else {
 mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
 }
 
 
 if (mParent != null) {
 mParent.requestDisallowInterceptTouchEvent(disallowIntercept);
 }
 }
 
 | 
通过 requestDisallowInterceptTouchEvent 设置好 FLAG 后,在 ViewGroup 的事件分发机制中可以看到:  
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 
 | @Override
 public boolean dispatchTouchEvent(MotionEvent ev) {
 ...
 boolean handled = false;
 if (onFilterTouchEventForSecurity(ev)) {
 ...
 
 final boolean intercepted;
 if (actionMasked == MotionEvent.ACTION_DOWN
 || mFirstTouchTarget != null) {
 
 final boolean disallowIntercept =
 (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
 if (!disallowIntercept) {
 intercepted = onInterceptTouchEvent(ev);
 ev.setAction(action);
 } else {
 intercepted = false;
 }
 } else {
 intercepted = true;
 }
 ...
 ...
 }
 
 | 
参考链接
- http://www.jianshu.com/p/e99b5e8bd67b
- http://www.jianshu.com/p/7daf0feb6c2d  
- http://blog.csdn.net/guolin_blog/article/details/9097463/  
- http://blog.csdn.net/guolin_blog/article/details/9153747/  
- http://www.cnblogs.com/duoduohuakai/p/3996385.html  
- http://www.cnblogs.com/sunzn/archive/2013/05/10/3064129.html  
- http://blog.csdn.net/carson_ho/article/details/54136311