編輯:關於Android編程
如果想參與實際開發項目,若不理解事件分發回傳機制的話,幾乎等於“”摸黑抓鳅”,因為幾乎每個項目都會出現滑動沖突問題;而要想解決滑動沖突問題,必須先了解甚至掌握事件分發傳遞機制。等到了解決滑動沖突時,至少沒有一種“斷層”的感覺。所以本專欄開篇先介紹事件機制,對安卓中的事件機制,做一個詳細的介紹與分析。
首先,View的幾個基本的繼承關系:
本博客案例的圖層:
新建三個類(分別按照上邊圖解的方式,寫出這幾個有關事件的方法)。
這個很簡單,就不羅列了。例如類似容器1的代碼:
public class ViewGroupOne extends LinearLayout { public ViewGroupOne(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } public ViewGroupOne(Context context) { super(context); // TODO Auto-generated constructor stub } /** * 分發事件 */ @Override public boolean dispatchTouchEvent(MotionEvent event) { ActionUtiles.processEvent(event, "ViewGroupOne+分發+dispatchTouchEvent"); return super.dispatchTouchEvent(event); } /** * 攔截事件 */ @Override public boolean onInterceptTouchEvent(MotionEvent event) { ActionUtiles.processEvent(event, "ViewGroupOne+攔截+onInterceptTouchEvent"); return super.onInterceptTouchEvent(event); } /** * 處理事件 */ @Override public boolean onTouchEvent(MotionEvent event) { ActionUtiles.processEvent(event, "ViewGroupOne+處理+onTouchEvent"); return true; } }筆者是吧事件抽取成工具類了,當然,每個方法裡都寫都寫一遍事件情況也無所謂,只不過重復了一些代碼罷了。
接著寫一個復合上邊圖解的布局:
注意:記得寫類的全稱。
好了,廢話不多說,直接運行程序說話。通多點擊手機屏幕。對所有的可能情況全部羅列如下:
事件1:點擊紅色位置。看log輸出
可以看到,整個事件是Activity先得到事件,調用它的dispatchTouchEvent分發事件,傳遞給ViewGroupOne,調用ViewGroupOne的dispatchTouchEvent方法,此時這個返回值默認return super.dispatchTouchEvent(event);把事件傳遞給自己的onInterceptTouchEvent(MotionEvent event)攔截事件,它的返回值也是默return super.onInterceptTouchEvent(event);認,即沒做攔截;自己的onTouchEvent(MotionEvent event)處理方法被調用,默認不處理,return super.onTouchEvent(event);。這樣事件沒有被消費,又返回給Activity的onTouchEvent(MotionEvent event) ,Activity也是默認返回值。事件銷毀。由up事件log日志,也可以看到:最後松手時,已經與ViewGroupOne沒有任何關系。
事件2:點擊綠色區域l。看log輸出:
這裡就會顯而易見了。多了ViewGroupTwo,就多往下傳遞一層,最裡面這層每做處理,最後還是回傳回來。到activity事件全部消失
事件3:點擊藍色區域:
這個肯定在意料之中,不用解釋也很清楚為何打印此log了。
處理1:藍色區域,MyTextView修改如下代碼:
@Override public boolean onTouchEvent(MotionEvent event) { ActionUtiles.processEvent(event, "MyTextView+處理+onTouchEvent"); return true;//事件消費,不回傳 }此時要重新運行程序了再點擊藍色區域,看log:
MyTextView的onTouchEvent(MotionEvent event)返回true的意思是,事件由我來處理。它處理了事件,就不可能出現回傳了,出現這種log也是順理成章了。再看UP事件與分發攔截是一致的。最後在MyTextView中消失。這個時候可以對比一了,一都是默認,可以稱之為狹義的回傳機制,而二的處理1:我們可以稱之為狹義的攔截機制,每一次的往下分發,有可稱為狹義的傳遞機制(稱之為狹義,可能逼格略高些,是因為不能代表全部,卻也不失一般性;最起碼攔截與回傳分發大致是什麼很清楚了)。那接著就細致開來,從狹義走到廣義。
處理2:藍色區域,MyTextView修改如下代碼:
@Override public boolean onTouchEvent(MotionEvent event) { ActionUtiles.processEvent(event, "MyTextView+處理+onTouchEvent"); return false;//和默認效果一樣,回傳機制 }再運行,打印看log:
和默認效果是一樣的。回看默認解析。
TextView(沒有子組件類型)
onTouchEvent()
return true; //事件消費不回傳,自己消費掉事件
return false;或者 return super.onTouchEvent() ;//事件回傳給父組件
處理3:ViewGroupOne的dispatchTouchEvent方法做如下修改:
@Override public boolean dispatchTouchEvent(MotionEvent event) { ActionUtiles.processEvent(event, "ViewGroupOne+分發+dispatchTouchEvent"); return true; }運行程序,點擊藍色位置看log:
其實你會發現。不管點擊屏幕哪個位置,都打印這樣的log
這是因為,ViewGroupOne的dispatchTouchEvent返回true了,相當於在ViewGroupOne的分發事件地方就攔截了事件(稱之為攔截,也因為沒有回傳,從UP日志裡也可以看出沒有回傳)。事件消失。
處理4:ViewGroupOne的dispatchTouchEvent方法做如下修改:
@Override public boolean dispatchTouchEvent(MotionEvent event) { ActionUtiles.processEvent(event, "ViewGroupOne+分發+dispatchTouchEvent"); return false; }
返回false,表示自己的dispatchTouchEvent不做處理,即不做分發。就回傳,回傳給activity的onTouchEvent處理,最後事件消失
注意:ViewGroupOne的dispatchTouchEvent方法默認返回super.dispatchTouchEvent(event);的時候是要傳遞給自己的onTouchEvent方法的,問這個方式是否做攔截。上邊其實已經不知不覺介紹了這個情況。此時可以總結,只有在ViewGroupOne的dispatchTouchEvent方法默認返回super.dispatchTouchEvent(event);的時候才會去調用自己的onInterceptTouchEvent(MotionEvent event) 攔截事件,是否攔截。其他都是回傳
處理5:ViewGroupOne的onInterceptTouchEvent方法做如下修改:
@Override public boolean onInterceptTouchEvent(MotionEvent event) { ActionUtiles.processEvent(event, "ViewGroupOne+攔截+onInterceptTouchEvent"); return true; }log情況
自己的onInterceptTouchEvent(MotionEvent event)攔截事件返回為true,表名自己要攔截,不向下傳遞。調用自己的onTouchEvent(MotionEvent event)是否處理。由於默認不處理,又回傳到activity事件消失。
處理6:ViewGroupOne的onInterceptTouchEvent(MotionEvent event)攔截事件返回false
@Override public boolean onInterceptTouchEvent(MotionEvent event) { ActionUtiles.processEvent(event, "ViewGroupOne+攔截+onInterceptTouchEvent"); return false; }
又是默認的機制。
處理7:ViewGroupOne的onTouchEvent做如下處理:
注意:這個方法想要執行,前提是在ViewGroupOne的onInterceptTouchEvent方法返回true的時候
@Override public boolean onTouchEvent(MotionEvent event) { ActionUtiles.processEvent(event, "ViewGroupOne+處理+onTouchEvent"); return super.onTouchEvent(event); }
返回true,自己處理事件,也就沒了回傳機制。事件消失
處理8:ViewGroupOne的onTouchEvent返回為false。不用打印也可以清楚,與默認效果是一樣的。
2,ViewGroup
dispatchTouchEvent
return true;//自己消費,不往下(子組件)往上傳遞(不回傳)
return false;//自己不處理,回傳給父組件onTouchEvent方法處理
return super.dis.....;//問自己onInterceptTouchEvent是否攔截
問自己>onInterceptTouchEvent
true: 自己消費,調用自己onTouchEvent();不往下傳遞
false 或super: 默認往下傳遞
>onTouchEvent()
true: 自己消費(不回傳)
false 或 super: 繼續回傳
對於ViewGroupTwo和One是一摸一樣的。就不再多贅述。最後,再用一張草圖做一個收尾::
此草圖花費接近一小時時間。。。雖然潦草,但是最能說明問題,包含了所有可能的情況。。
對於攔截機制詳細介紹就完畢了,但是除了上邊這些情況外,還有許許多多的分支情況;但是大同小異,仔細分析一下,就能得出正確的結論。以後此專欄可能還會再次探討類似問題。若有問題或建議請留言更正、補充。
筆者花費幾個小時,您或許只需要10分鐘。歡迎點贊或關注本專欄,Android進階知識不定期會更新哦。也可關注Android簡易實戰教程專欄,花5分鐘“欣賞”有趣的小案例。
什麼是通信?通信 ,顧名思義,指的就是信息的傳遞或者交換看完本文能收獲什麼?按目錄索引,你可以學習到1. 組件間的通信,Activity,fragment,Service
功能非常簡單就是定義一個CountDownTimer直接看代碼 首先在XML裡面放個按鈕代碼如下: 下面就是主代碼: p
榮耀6plus有著紅外遙控功能,相信入手榮耀6plus的同學都很想試試自己的手機當遙控是什麼感覺吧。華為榮耀6plus不僅僅是手機,不僅可以做智能手機,下載
今天的Demo比較簡單,就是簡單的把View的內容轉化成Bitmap,先來個效果圖: 看圖是不是有點不知所雲,哈哈,聽我細細道來,首先我用一個Linear