事件分發(fā)機制
舉個例子:
ViewGroup1----->ViewGroup----->View
-
默認的時候:(View可點擊)
點擊事件會由外向內(nèi)傳遞,每一個動作都會發(fā)生事件的傳遞
//-----------------Down--------------------------- E/ViewGroup1: dispatchTouchEvent: viewgroup1---- E/ViewGroup1: onInterceptTouchEvent: viewgroup1---- E/ViewGroup: dispatchTouchEvent: viewgroup---- E/ViewGroup: onInterceptTouchEvent: viewgroup---- E/Button1: dispatchTouchEvent: button1---- E/Button1: onTouchEvent: button1---- E/Button1: onTouchEventDown: button1---- //===================Up======================== E/ViewGroup1: dispatchTouchEvent: viewgroup1---- E/ViewGroup1: onInterceptTouchEvent: viewgroup1---- E/ViewGroup: dispatchTouchEvent: viewgroup---- E/ViewGroup: onInterceptTouchEvent: viewgroup---- E/Button1: dispatchTouchEvent: button1---- E/Button1: onTouchEvent: button1---- E/Button1: onTouchEventUp: button1----
-
默認的時候:(View不可點擊)
當點擊事件分發(fā)到最底層的時候,并且最底層的子View沒有消費時間的能力時,此時會將Down事件交由它的父布局進行處理言蛇,如果父布局處理不了,逐級上傳兽狭,一直到Activity
E/ViewGroup1: dispatchTouchEvent: viewgroup1---- E/ViewGroup1: onInterceptTouchEvent: viewgroup1---- E/ViewGroup: dispatchTouchEvent: viewgroup---- E/ViewGroup: onInterceptTouchEvent: viewgroup---- E/Button1: dispatchTouchEvent: button1---- E/Button1: onTouchEvent: button1---- E/Button1: onTouchEventDown: button1---- E/ViewGroup: onTouchEvent: viewgroup---- E/ViewGroup: onTouchEventDown: viewgroup---- E/ViewGroup1: onTouchEvent: viewgroup1---- E/ViewGroup1: onTouchEventDown: viewgroup1----
-
View的父布局攔截事件(onInterceptTouchEvent ------> true)
當點擊事件在ViewGroup處進行攔截的時候,Down事件將不會再傳遞到他的子View,同時鹿蜀,他回交由自己的onTouchEvent方法進行事件的處理箕慧,如果沒有處理能力,則將時間逐級上傳茴恰,直到Activity
E/ViewGroup1: dispatchTouchEvent: viewgroup1---- E/ViewGroup1: onInterceptTouchEvent: viewgroup1---- E/ViewGroup: dispatchTouchEvent: viewgroup---- E/ViewGroup: onInterceptTouchEvent: viewgroup---- E/ViewGroup: onTouchEvent: viewgroup---- E/ViewGroup: onTouchEventDown: viewgroup---- E/ViewGroup1: onTouchEvent: viewgroup1---- E/ViewGroup1: onTouchEventDown: viewgroup1----
-
View的父布局攔截事件(onInterceptTouchEvent ------> true ,onTouchEvent----->true)
onTouchEvent----->true:表示事件可以在此方法內(nèi)消費掉销钝,所以ViewGroup不會再將Down事件交由它的上級進行處理。
//=======================Down======================= E/ViewGroup1: dispatchTouchEvent: viewgroup1---- E/ViewGroup1: onInterceptTouchEvent: viewgroup1---- E/ViewGroup: dispatchTouchEvent: viewgroup---- E/ViewGroup: onInterceptTouchEvent: viewgroup---- E/ViewGroup: onTouchEvent: viewgroup---- E/ViewGroup: onTouchEventDown: viewgroup---- //======================Up====================== E/ViewGroup1: dispatchTouchEvent: viewgroup1---- E/ViewGroup1: onInterceptTouchEvent: viewgroup1---- E/ViewGroup: dispatchTouchEvent: viewgroup---- E/ViewGroup: onTouchEvent: viewgroup---- E/ViewGroup: onTouchEventUp: viewgroup----
-
最外層的ViewGroup1攔截事件(onInterceptTouchEvent ------> true)
事件將到此為止琐簇,交給自己的onTouchEvent進行處理蒸健,不能處理的話則交由上級座享。
可以在布局里設置clickable="true",或者是onTouchEvent返回true
//====================clickable="false"============================ E/ViewGroup1: dispatchTouchEvent: viewgroup1---- E/ViewGroup1: onInterceptTouchEvent: viewgroup1---- E/ViewGroup1: onTouchEvent: viewgroup1---- E/ViewGroup1: onTouchEventDown: viewgroup1---- //=========================clickable="true"=============================== E/ViewGroup1: dispatchTouchEvent: viewgroup1---- E/ViewGroup1: onInterceptTouchEvent: viewgroup1---- E/ViewGroup1: onTouchEvent: viewgroup1---- E/ViewGroup1: onTouchEventDown: viewgroup1---- E/ViewGroup1: dispatchTouchEvent: viewgroup1---- E/ViewGroup1: onTouchEvent: viewgroup1---- E/ViewGroup1: onTouchEventMove: viewgroup1---- E/ViewGroup1: dispatchTouchEvent: viewgroup1---- E/ViewGroup1: onTouchEvent: viewgroup1---- E/ViewGroup1: onTouchEventUp: viewviewgroup1----
當ViewGroup和View都有消費事件的能力時似忧,情況和第一種其實是一樣的渣叛,因為時間能夠不被攔截,一直傳遞盯捌,所以在View的時候淳衙,已經(jīng)把他消費掉了,就沒有了饺著。
-
當ViewGroup1的dispatchTouchEvent------>false時:
E/ViewGroup1: dispatchTouchEvent: viewgroup1----
-
當ViewGroup的dispatchTouchEvent------>false時:
表示事件不在分發(fā)下去箫攀,Down事件交由它的父布局進行處理,父布局處理不了幼衰,則再往上遞交靴跛,一直到Activity
//---------0表示的是Down事件-----1表示Up事件 E/ViewGroup1: dispatchTouchEvent: viewgroup1----0 E/ViewGroup1: onInterceptTouchEvent: viewgroup1----0 E/ViewGroup: dispatchTouchEvent: viewgroup----0 //-----------ViewGroup1的onTouchEvent返回false時 E/ViewGroup1: onTouchEvent: viewgroup1----0 E/ViewGroup1: onTouchEventDown: viewgroup1----0 //-----------ViewGroup1的onTouchEvent返回true時 E/ViewGroup1: onTouchEvent: viewgroup1----0 E/ViewGroup1: onTouchEventDown: viewgroup1----0 E/ViewGroup1: dispatchTouchEvent: viewgroup1----1 E/ViewGroup1: onTouchEvent: viewgroup1----1 E/ViewGroup1: onTouchEventUp: viewviewgroup1----1
-
View.setOnClickListener/View.setOnTouchListener-----false
onTouch方法要優(yōu)先于onClick方法執(zhí)行
E/ViewGroup1: dispatchTouchEvent: viewgroup1----0 E/ViewGroup1: onInterceptTouchEvent: viewgroup1----0 E/ViewGroup: dispatchTouchEvent: viewgroup---- E/ViewGroup: onInterceptTouchEvent: viewgroup---- E/Button1: dispatchTouchEvent: button1---- E/MainActivity: onTouch: button1 E/Button1: onTouchEvent: button1---- E/Button1: onTouchEventDown: button1---- E/ViewGroup1: dispatchTouchEvent: viewgroup1----1 E/ViewGroup1: onInterceptTouchEvent: viewgroup1----1 E/ViewGroup: dispatchTouchEvent: viewgroup---- E/ViewGroup: onInterceptTouchEvent: viewgroup---- E/Button1: dispatchTouchEvent: button1---- E/MainActivity: onTouch: button1 E/Button1: onTouchEvent: button1---- E/Button1: onTouchEventUp: button1---- E/MainActivity: onClick: button1
View.setOnClickListener/View.setOnTouchListener-----true
E/ViewGroup1: dispatchTouchEvent: viewgroup1----0
E/ViewGroup1: onInterceptTouchEvent: viewgroup1----0
E/ViewGroup: dispatchTouchEvent: viewgroup----
E/ViewGroup: onInterceptTouchEvent: viewgroup----
E/Button1: dispatchTouchEvent: button1----
E/MainActivity: onTouch: button1
E/ViewGroup1: dispatchTouchEvent: viewgroup1----1
E/ViewGroup1: onInterceptTouchEvent: viewgroup1----1
E/ViewGroup: dispatchTouchEvent: viewgroup----
E/ViewGroup: onInterceptTouchEvent: viewgroup----
E/Button1: dispatchTouchEvent: button1----
E/MainActivity: onTouch: button1
說說原理:
一段偽代碼開路
public boolean dispatchTouchEvent(MotionEvent ev) {
boolean consume = false;//事件是否被消費
if (onInterceptTouchEvent(ev)){//調(diào)用onInterceptTouchEvent判斷是否攔截事件
consume = onTouchEvent(ev);//如果攔截則調(diào)用自身的onTouchEvent方法
}else{
consume = child.dispatchTouchEvent(ev);//不攔截調(diào)用子View的dispatchTouchEvent方法
}
return consume;//返回值表示事件是否被消費,true事件終止渡嚣,false調(diào)用父View的onTouchEvent方法
}
//來自于:http://www.reibang.com/p/238d1b753e64
特別強調(diào)
- 子View可以通過requestDisallowInterceptTouchEvent方法干預父View的事件分發(fā)過程(ACTION_DOWN事件除外)
- 對于View(注意梢睛!ViewGroup也是View)而言,如果設置了onTouchListener识椰,那么OnTouchListener方法中的onTouch方法會被回調(diào)绝葡。onTouch方法返回true,則onTouchEvent方法不會被調(diào)用(onClick事件是在onTouchEvent中調(diào)用)所以三者優(yōu)先級是onTouch->onTouchEvent->onClick
- View 的onTouchEvent 方法默認都會消費掉事件(返回true)腹鹉,除非它是不可點擊的(clickable和longClickable同時為false)藏畅,View的longClickable默認為false,clickable需要區(qū)分情況功咒,如Button的clickable默認為true愉阎,而TextView的clickable默認為false。