国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android View事件分發和消費源碼簡單理解

2019-10-22 18:32:42
字體:
來源:轉載
供稿:網友

Android View事件分發和消費源碼簡單理解

前言:

開發過程中覺得View事件這塊是特別燒腦的,看了好久,才自認為看明白。中間上網查了下singwhatiwanna粉絲的讀書筆記,有種茅塞頓開的感覺。

很重要的學習方法:化繁為簡,只抓重點。

源碼一坨,不要指望每一行代碼都看懂。首先是沒必要,其次大量非關鍵代碼會讓你模糊真正重要的部分。
以下也只是學姐的學習成果,各位同學要想理解深刻,還需要自己親自去看源碼。

2.源碼分析

由于源碼實在太長,而且也不容易看懂,學姐這里就不貼出來了,因為沒必要。

以下是學姐簡化版源碼。

(1)ViewGroup.dispatchTouchEvent(event)

boolean dispatchTouchEvent(MotionEvent event) { int action = event.getAction(); //判斷ViewGroup是否攔截touch事件。當為ACTION_DOWN或者找到能夠接收touch事件的子View 時,由onInterceptTouchEvent(event)決定是否攔截。其他情況,即ACTION_MOVE/ACTION_UP且 沒找到能夠接收touch事件的子View時,直接攔截。 boolean intercepted; if (action == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) {  intercepted = onInterceptTouchEvent(event); } else {  intercepted = true; } //如果ViewGroup不攔截touch事件。在ACTION_DOWN時遍歷所有子View,查找能夠接收touch事件的 子View。如果找到則設置mFirstTouchTarget,并跳出循環。 boolean alreadyDispatchedToNewTouchTarget = false; if (!intercepted) {  if (action == MotionEvent.ACTION_DOWN) {   for (int i = childrenCount - 1; i >= 0; i--) {    if (!canViewReceivePointerEvents(child) ||     !isTransformedTouchPointInView(x, y, child, null)) {      continue;    }    if (dispatchTransformedTouchEvent(event, child)) {     //找到mFirstTouchTarget     newTouchTarget = addTouchTarget(child);     alreadyDispatchedToNewTouchTarget = true;     break;    }    }   } } //事件下發及消費。如果沒找到能夠接收touch事件的子View,則由ViewGroup自己處理及消費。 如果找到能夠接收touch事件的子View,則由子View遞歸處理touch事件及消費。 boolean handled = false; if (mFirstTouchTarget == null) {  handled = dispatchTransformedTouchEvent(event, null); } else {  if (alreadyDispatchedToNewTouchTarget) {   handled = true;  } else {   while (touchTarget) {    handled = dispatchTransformedTouchEvent(event, child);   }  } } return handled;}//ViewGroup事件下發。如果無接收touch事件的子View,則由ViewGroup的父類(即View)下發touch事件如果child非空,則交由子View下發touch事件,子View可以是ViewGroup或View。boolean dispatchTransformedTouchEvent(MotionEvent event, View child) { boolean handled; if (child == null) {  handled = super.dispatchTouchEvent(event); } else {  handled = child.dispatchTouchEvent(event); } return handled;}

(2)View.dispatchTouchEvent(event)

//View的Touch事件分發。當外部設置了mOnTouchListener時,先交由mOnTouchListener.onTouch(event)消費。若未消費,則交給View的onTouchEvent(event)消費。onTouchEvent的實現是,如果設置了mOnClickListener,則執行mOnClickListener.onClick()點擊事件。返回值為true,表示消費,否則未消費。boolean dispatchTouchEvent(MotionEvent event) { boolean result = false; if (mOnTouchListener != null && mOnTouchListener.onTouch(this, event)) {   result = true; } if (!result && onTouchEvent(event)) {  result = true; } return result;}boolean onTouchEvent(MotionEvent event) { performClick();}

3.總結

總結下ViewGroup的事件分發及消費過程:

整個過程包括3個部分:判斷是否攔截 -> 查找接收touch事件的子View -> 事件下發及消費

判斷是否攔截:

(1) ACTION_DOWN 或者 非ACTION_DOWN且找到接收touch事件的子View時,由onInterceptTouchEvent(event)決定是否攔截

(2) 非ACTION_DOWN,且未找到接收touch事件的子View時,標明需要攔截touch事件

這里解釋下,影響ViewGroup是否能攔截touch事件有2個因素:是否 找到了接收touch事件的子View 和 onInterceptTouchEvent(event). 而查找接收touch事件的子View這一過程只需要在ACTION_DOWN的時候確定好就行。如果ACTION_DOWN的時候沒找到,那么ACTION_MOVE和ACTION_UP肯定也找不到,因此touch事件直接被ViewGroup攔截。如果找到了接收touch事件的子View,那么ACTION_MOVE和ACTION_UP情況下還是要檢查下ViewGroup的onInterceptTouchEvent(event),看下是否攔截。

查找接收touch事件的子View:

(1) 兩種情況下查找:ACTION_DOWN且ViewGroup不攔截的情況下。

(2) 查找方法:遍歷所有子View,如果touch事件的xy坐標在該ViewGroup的某個子View范圍內,則針對該子View執行遞歸分發touch事件操作,如果找到有子View處理touch事件(return true),則跳出循環。

這里解釋下查找條件。查找接收touch事件的子View,顯然只需要ACTION_DOWN情況下即可,沒必要ACTION_MOVE和ACTION_UP都檢查,否則重復操作。如果ViewGroup都已經攔截了,顯然不需要再去考慮子View怎么樣了。

事件下發及消費:

(1)兩種情況:ViewGroup下發及消費 或者 ViewGroup的子View下發及消費

(2)如果經過以上兩步,沒找到接收Touch事件的子View,那么由ViewGroup進行下發及消費,下發及調用流程是:ViewGroup.dispatchTouchEvent -> View.dispatchTouchEvent -> mOnTouchListener.onTouch -> onTouchEvent -> onClick

(3)如果找到接收touch事件的子View,則針對該子View執行touch事件遞歸下發及消費的操作

補充:

(1) 源碼中,mFirstTouchEvent表示接收touch事件的子View

(2) 步驟2和3,都有執行dispatchTransformedTouchEvent(event, child)的操作,步驟2中只是為了查找接收touch事件的子View,步驟3主要目的是進行事件分發及消費。如果步驟2中針對某個子View已經執行了該方法,則步驟3中不再重復執行。個人理解,不知道是否有誤。

4.結論

(1) 回調方法

ViewGroup:dispatchTouchEvent -> onInterceptTouchEvent -> onTouchEvent

View: dispatchTouchEvent -> onTouch

(2) 調用順序

Action執行順序:ACTION_DOWN -> ACTION_MOVE -> ACTION_UP

ViewGroup: dispatchTouchEvent -> onInterceptTouchEvent -> onTouchEvent()

View: dispatchTouchEvent -> onTouchEvent

事件分發傳遞順序: Parent View -> Child View

ViewGroup1.dispatchTouchEvent -> ViewGroup2.dispatchTouchEvent
-> View3.dispatchTouchEvent
(緊跟著是View3.onTouchEvent)

事件消費傳遞順序:Child View -> Parent View

View3.onTouchEvent -> ViewGroup2.onTouchEvent
-> ViewGroup1.onTouchEvent

個人理解這種傳遞順序,是由dispatchTransformedTouchEvent引起的,這里就是遞歸調用,整個事件的入口就是ViewGroup.dispatchTouchEvent.

以上就是Android View事件分發和消費源碼的文章分享,關于Android view事件的分發機制大家可以在本站搜索相應的文章進行擴展學習!

感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 桓台县| 唐山市| 外汇| 桂东县| 石渠县| 武平县| 辽源市| 冀州市| 广宁县| 霍城县| 额尔古纳市| 吴川市| 甘孜| 深圳市| 富蕴县| 东兴市| 通化市| 申扎县| 伊金霍洛旗| 睢宁县| 石泉县| 阳东县| 宁远县| 柳河县| 五台县| 肥乡县| 英吉沙县| 阿鲁科尔沁旗| 礼泉县| 开远市| 晋江市| 南京市| 安庆市| 德令哈市| 南部县| 乌苏市| 纳雍县| 乡城县| 资溪县| 宿松县| 灵寿县|