一.Android View框架提供了3個對事件的主要操作概念。
1、事件的分發機制,dispatchTouchEvent。主要是parent根據觸摸事件的產生位置,以及child是否愿意負責處理該系列事件等狀態,向其child分發事件的機制。
2、事件的攔截機制,onInterceptTouchEvent。主要是parent根據它內部的狀態、或者child的狀態,來把事件攔截下來,阻止其進一步傳遞到child的機制。
3、事件的處理機制,onTouchEvent。主要是事件序列的接受者(可以是一個View或者ViewGroup),對事件作出處理,并且向其parent傳遞處理結果的機制。
二.在Java中,傳遞計算結果,有很多種途徑,這里采用的是一種適用于同步調用的方法,返回值的方法。每個機制都使用boolean類型作為其返回值,那么每個機制的每個返回值是什么含義呢。
1、事件的分發機制,dispatchTouchEvent。
true-事件被以該節點為根節點的View樹成功處理,此時該事件就算是處理完成了,事件不會再向上返還給View的父節點(把事件分發過來的那個節點)。
false-以該節點為根節點的View樹種,沒有一個View(包括該View)成功處理了此事件,所以事件會向上返還給View的父節點(把事件分發過來的那個節點)。
2、事件的攔截機制,onInterceptTouchEvent。主要是parent根據它內部的狀態、或者child的狀態,來把事件攔截下來,阻止其進一步傳遞到child的機制。
true-當前ViewGroup(因為View中沒有該方法,而沒有child的VIew也不需要有攔截機制)希望該事件不再傳遞給其child,而是希望自己處理。
false-當前ViewGroup不準備攔截該事件,事件正常向下分發給其child。
3、事件的處理機制,onTouchEvent。主要是事件序列的接受者(可以是一個View或者ViewGroup),對事件作出處理,并且向其parent傳遞處理結果的機制。
true-表示該View成功處理了該事件,該處理結果會向上通知給其parent。
false-表示該View沒有成功處理該事件,那么它的parent會有機會來處理該事件(parent標記為事件序列接受者,parent 的 onTouchEvent 在 Down 事件時返回true)。
三.源代碼分析
View:
1、dispatchTouchEvent:
/** 把事件分發到目標對象,因為這里是View對象,默認不含有child,所以這里他會把事件分發給自己 */
public boolean dispatchTouchEvent(MotionEvent event);
public boolean dispatchTouchEvent(MotionEvent event){ boolean result = false; //如果有事件監聽器,先讓監聽器處理事件。 if (mOnTouchListener.onTouch(event)) { //如果監聽器成功處理了該事件,處理結果設置為true。 result = true; } //如果沒有監聽器,就調用自身的onTouchEvent方法來處理事件。 if (!resutlt && onTouchEvent(event)) { //如果自身的onTouchEvent成功處理事件,處理結果設置為true。 result = true; } return result; } ViewGroup:
1、onInterceptTouchEvent
/** 默認實現是返回false,也就是默認不攔截任何事件 */
public boolean onInterceptTouchEvent(MotionEvent ev);
2、dispatchTouchEvent
/** 根據內部攔截狀態,向其child或者自己分發事件 */
public boolean dispatchTouchEvent(MotionEvent ev);
public boolean dispatchTouchEvent(MotionEvent ev) { if (ACTION_DOWN事件 || 沒有事件處理對象) { if (允許攔截事件,該標志位由child調用requestDisallowInterceptTouchEvent<span style="font-family:微軟雅黑;font-size:14px;">設置</span>) { //查詢攔截機制的結果,根據該結果來判斷是否需要攔截 intercepted = onInterceptTouchEvent(ev); } else { //不允許攔截,那么不攔截 intercepted = false; } } else { //不是DOWN,并且有處理對象,允許攔截,中斷事件傳遞 intercepted = true; } if (不取消 && 不攔截) { if (ACTION_DOWN) { //找尋接收事件序列的對象,其他事件不需要再計算事件產生對象,試想一下滑動一個ListView,當手指滑動出ListView的范圍時,依然還是ListView響應后續事件。 for (遍歷所有childView) { if (觸摸點不在childView內部) { continue; } if (childView.dispatchTouchEvent(event)) { 保存處理該事件的View,后續事件直接傳遞到該View,不要重新計算; } } } if (還沒有事件處理對象) { //當前View樹中沒找到合適的child處理對象,把事件給自己處理,View.dispatchTouchEvent()就是把事件分發給自己 super.dispatchTouchEvent(event); } else { //傳遞給child childView.dispatchTouchEvent(event); } } else if (攔截) { //攔截事件,把事件給自己處理,View.dispatchTouchEvent()就是把事件分發給自己 super.dispatchTouchEvent(event); } return 處理結果; } 3、requestDisallowInterceptTouchEvent
/** 干澀parent的事件分發機制,通知parent,是否攔截后續事件,如果設置為true,parent就不會攔截該事件,不管什么狀態。設置為false,parent走正常的攔截流程 */
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept);
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { if (已經是當前要設置的狀態) { // 已經處于這個狀態, 假設我們的parent也是這個狀態 return; } 設置該狀態; // 傳遞給parent if (有父容器) { 設置父容器的攔截狀態; } } 以上就是本文的全部內容,希望本文的內容對大家的學習或者工作能帶來一定的幫助,同時也希望多多支持武林網!
新聞熱點
疑難解答