*****
**事件分發流程**
[TOC=6]
# 1. 事件分發機制方法&流程介紹
## 先搞明白Activity的dispatchTouchEvent()
[參考博客](https://blog.csdn.net/hzmming2008/article/details/82347416)
## 1.1 事件分發機制方法
事件分發過程由dispatchTouchEvent() 、onInterceptTouchEvent()和onTouchEvent()三個方法協助完成,如下圖:

方法詳細介紹
* Android事件分發流程如下:(**必須熟記**)
> Android事件分發順序:**Activity(Window) -> ViewGroup -> View**

事件分發機制詳細流程
其中:
* super:調用父類方法
* true:消費事件,即事件不繼續往下傳遞
* false:不消費事件,事件也不繼續往下傳遞 / 交由給父控件onTouchEvent()處理
**接下來,我將詳細介紹這3個方法及相關流程。**
## 1.2 dispatchTouchEvent()
| 屬性 | 介紹 |
| --- | --- |
| 使用對象 | Activity、ViewGroup、View |
| 作用 | 分發點擊事件 |
| 調用時刻 | 當點擊事件能夠傳遞給當前View時,該方法就會被調用 |
| 返回結果 | 是否消費當前事件,詳細情況如下: |
**1\. 默認情況:根據當前對象的不同而返回方法不同**
| 對象 | 返回方法 | 備注 |
| --- | --- | --- |
| Activity | super.dispatchTouchEvent() | 即調用父類ViewGroup的dispatchTouchEvent() |
| ViewGroup | onIntercepTouchEvent() | 即調用自身的onIntercepTouchEvent() |
| View | onTouchEvent() | 即調用自身的onTouchEvent() |

流程解析
**2\. 返回true**
* 消費事件
* 事件不會往下傳遞
* 后續事件(Move、Up)會繼續分發到該View
* 流程圖如下:

流程圖
**3\. 返回false**
* 不消費事件
* 事件不會往下傳遞
* 將事件回傳給父控件的onTouchEvent()處理
> Activity例外:返回false=消費事件
* 后續事件(Move、Up)會繼續分發到該View(與onTouchEvent()區別)
* 流程圖如下:

流程圖
## 1.3 onTouchEvent()
| 屬性 | 介紹 |
| --- | --- |
| 使用對象 | Activity、ViewGroup、View |
| 作用 | 處理點擊事件 |
| 調用時刻 | 在dispatchTouchEvent()內部調用 |
| 返回結果 | 是否消費(處理)當前事件,詳細情況如下: |
> 與dispatchTouchEvent()類似
**1\. 返回true**
* 自己處理(消費)該事情
* 事件停止傳遞
* 該事件序列的后續事件(Move、Up)讓其處理;
* 流程圖如下:

流程圖
**2\. 返回false(同默認實現:調用父類onTouchEvent())**
* 不處理(消費)該事件
* 事件往上傳遞給父控件的onTouchEvent()處理
* 當前View不再接受此事件列的其他事件(Move、Up);
* 流程圖如下:

流程圖
## 1.4 onInterceptTouchEvent()
| 屬性 | 介紹 |
| --- | --- |
| 使用對象 | ViewGroup(注:Activity、View都沒該方法) |
| 作用 | 攔截事件,即自己處理該事件 |
| 調用時刻 | 在ViewGroup的dispatchTouchEvent()內部調用 |
| 返回結果 | 是否攔截當前事件,詳細情況如下: |

返回結果
* 流程圖如下:

流程圖
## 1.5 三者關系
下面將用一段偽代碼來闡述上述三個方法的關系和點擊事件傳遞規則
~~~
public boolean dispatchTouchEvent(MotionEvent ev) {
//代表是否消耗事件
boolean consume = false;
if (onInterceptTouchEvent(ev)) {
//如果onInterceptTouchEvent()返回true則代表當前View攔截了點擊事件
//則該點擊事件則會交給當前View進行處理
//即調用onTouchEvent ()方法去處理點擊事件
consume = onTouchEvent(ev);
} else {
//如果onInterceptTouchEvent()返回false則代表當前View不攔截點擊事件
//則該點擊事件則會繼續傳遞給它的子元素
//子元素的dispatchTouchEvent()就會被調用,重復上述過程
//直到點擊事件被最終處理為止
consume = child.dispatchTouchEvent(ev);
}
return consume;
}
~~~
## 1.5 總結
* 對于事件分發的3個方法,你了解嗎?
# 2. 幾個重要的事件
DOWN、MOVE、UP、CANCEL
# 3\. 事件分發場景介紹
下面我將利用例子來說明常見的點擊事件傳遞情況
### 3.1 背景描述
我們將要討論的布局層次如下:

布局層次
* 最外層:Activiy A,包含兩個子View:ViewGroup B、View C
* 中間層:ViewGroup B,包含一個子View:View C
* 最內層:View C
假設用戶首先觸摸到屏幕上View C上的某個點(如圖中黃色區域),那么Action\_DOWN事件就在該點產生,然后用戶移動手指并最后離開屏幕。
### 3.2 一般的事件傳遞情況
一般的事件傳遞場景有:
* 默認情況
* 處理事件
* 攔截DOWN事件
* 攔截后續事件(MOVE、UP)
### 3.2.1 默認情況
* 即不對控件里的方法(dispatchTouchEvent()、onTouchEvent()、onInterceptTouchEvent())進行重寫或更改返回值
* 那么調用的是這3個方法的默認實現:調用父類的方法
* 事件傳遞情況:(如圖下所示)
* 從Activity A---->ViewGroup B--->View C,從上往下調用dispatchTouchEvent()
* 再由View C--->ViewGroup B --->Activity A,從下往上調用onTouchEvent()

流程圖
注:雖然ViewGroup B的onInterceptTouchEvent方法對DOWN事件返回了false,后續的事件(MOVE、UP)依然會傳遞給它的onInterceptTouchEvent()
> 這一點與onTouchEvent的行為是不一樣的。
#### 3.2.2 處理事件
假設View C希望處理這個點擊事件,即C被設置成可點擊的(Clickable)或者覆寫了C的onTouchEvent方法返回true。
> 最常見的:設置Button按鈕來響應點擊事件
事件傳遞情況:(如下圖)
* DOWN事件被傳遞給C的onTouchEvent方法,該方法返回true,表示處理這個事件
* 因為C正在處理這個事件,那么DOWN事件將不再往上傳遞給B和A的onTouchEvent();
* 該事件列的其他事件(Move、Up)也將傳遞給C的onTouchEvent()

流程圖
#### 3.2.3 攔截DOWN事件
假設ViewGroup B希望處理這個點擊事件,即B覆寫了onInterceptTouchEvent()返回true、onTouchEvent()返回true。
事件傳遞情況:(如下圖)
* DOWN事件被傳遞給B的onInterceptTouchEvent()方法,該方法返回true,表示攔截這個事件,即自己處理這個事件(不再往下傳遞)
* 調用onTouchEvent()處理事件(DOWN事件將不再往上傳遞給A的onTouchEvent())
* 該事件列的其他事件(Move、Up)將直接傳遞給B的onTouchEvent()
> 該事件列的其他事件(Move、Up)將不會再傳遞給B的onInterceptTouchEvent方法,該方法一旦返回一次true,就再也不會被調用了。

流程圖
#### 3.2.4 攔截DOWN的后續事件
假設ViewGroup B沒有攔截DOWN事件(還是View C來處理DOWN事件),但它攔截了接下來的MOVE事件。
* DOWN事件傳遞到C的onTouchEvent方法,返回了true。
* 在后續到來的MOVE事件,B的onInterceptTouchEvent方法返回true攔截該MOVE事件,但該事件并沒有傳遞給B;這個MOVE事件將會被系統變成一個CANCEL事件傳遞給C的onTouchEvent方法
* 后續又來了一個MOVE事件,該MOVE事件才會直接傳遞給B的onTouchEvent()
> 1. 后續事件將直接傳遞給B的onTouchEvent()處理
> 2. 后續事件將不會再傳遞給B的onInterceptTouchEvent方法,該方法一旦返回一次true,就再也不會被調用了。
* C再也不會收到該事件列產生的后續事件。

流程圖
特別注意:
* 如果ViewGroup A 攔截了一個半路的事件(如MOVE),這個事件將會被系統變成一個CANCEL事件并傳遞給之前處理該事件的子View;
* 該事件不會再傳遞給ViewGroup A的onTouchEvent()
* 只有再到來的事件才會傳遞到ViewGroup A的onTouchEvent()
### 3.3 總結
* 對于Android的事件分發機制,你應該已經非常清楚了
- 咨詢項目實戰
- 第一單元 HTTP協議
- 1.1 OSI七層模型
- 1.2 HTTP協議(重點)
- 1.3 HTTPS協議(了解)
- 1.4 TCP/IP協議擴展
- 1.5 WebService簡介及實戰(無接口)
- 1.6 課后練習
- 第二單元 HTTPURLConnection
- 2.1 ANR
- 2.2 網絡判斷
- 2.3 HTTPURLConnection
- 2.4 課后練習
- 第三單元 AsyncTask
- 3.1 AsyncTask概述
- 3.2 AsyncTask基本使用
- 3.3 課后練習
- 第四單元 圖片異步加載
- 4.1 圖片異步加載概述
- 4.2 LruCache
- 4.3 DiskLRUCache
- 4.4 圖片三級緩存概述
- 4.5 封裝圖片加載緩存框架
- 第五單元 ListView多條目
- 5.1 ListView多條目概述
- 5.2 ListView多條目的使用
- 第六單元 ListView實現下拉刷新上拉加載
- 6.1 下拉刷新和上拉加載更多
- 6.2 XListView概述
- 6.3 XListView的使用
- 第七單元 封裝網絡框
- 7.1 封裝網絡框架概述
- 7.2 網絡框架的封裝
- 第八單元 項目介紹
- 8.1 公司項目團隊架構簡介
- 8.2 項目文檔及項目流程介紹
- 8.3 項目管理
- 8.4 項目開發
- 第九單元 項目框架搭建
- 9.1 基類封裝概述
- 9.2 Application中初始化配置
- 9.3 項目中的工具類
- 9.4 封裝網絡請求框架
- 9.5 封裝圖片異步緩存框架
- 第十單元 搭建UI框架1
- 10.1 側滑菜單概述
- 10.2 主界面框架搭建
- 第十一單元 搭建UI框架2
- 11.1 TabLayout的概述
- 11.2 TabLayout的使用
- 第十二單元 圖片上傳
- 12.1 圖片上傳概述
- 12.2 圖片上傳的實現
- 第十三單元 PullToRefresh
- 13.1 PullToRefresh概述
- 13.2 PullToRefresh的使用
- 13.3 緩存業務實現思路
- 第十四單元 事件分發及滑動沖突
- 14.1 事件分發概述
- 14.2 事件分發流程
- 14.3 事件分發的使用
- 第十五單元 傳感器的基本使用
- 15.1 傳感器概述
- 15.2 傳感器的使用
- 第十六單元 HTML與CSS復習
- 16.1 HTML
- 16.2 CSS
- 第十七單元 js復習
- 17.1 js基礎語法
- 17.2 js數組和內置對象
- 17.3 js常用事件
- 17.4 js對象模型
- 17.5 js 正則表達式
- 第十八單元 WebView
- 18.1 WebView 概述
- 18.2 WebView的使用
- 18.3 WebView與js交互
- 第十九單元 項目案例
- 項目概述
- 第二十單元 項目答辯
- 周考
- 第一周周考
- 第二周周考
- 第三種周考
- 月考
- 接口文檔