簡單的點擊事件處理是很容易的,要明白傳遞的流程有點困難,LZ研究事件傳遞的過程中被弄混了許多次,所以總結一下經驗,順便整理一下思路,幫助記憶。
一個佈局文件,如果只有單個按鈕,設置點擊事件是不需要再說了。
<span style="white-space:pre"> </span><Button
android:id="@id/btn"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
如果佈局文件包括ViewGroup(如RelativeLayout)和VIew(如Button),那麼就可以研究一下事件傳遞和處理的順序。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<Button
android:id="@id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
將RelativeLayout看成最底層的佈局,Button看成最高層的。
從最底層的佈局開始,RelativeLayout調用其dispathTouchEvent()方法(可以在父類ViewGroup中找到源碼)。從方法名或者註釋可以看出,這個是分發事件的意思。
根據dispathTouchEvent()的返回值:
1.true,已處理,不會向上傳遞,已經將事件分發給RelativeLayout;
2.false,未處理,繼續向上傳遞;
如果返回的是false,則繼續調用onInterceptTouchEvent(MotionEvent ev)。
從方法名或者註釋可以看出,這個是攔截事件的意思。
該方法默認返回false,可通過重寫改變其返回值。
根據其返回值的不同:
1.true,已處理,不會向上傳遞,等於將事件攔截;
2.false,未處理,繼續向上傳遞,沒有攔截;
需要注意的是,如果上述兩個方法有其中一個返回true,再有點擊事件的時候,就不會再進行判斷,而是直接給其onTouch()方法處理。
接下來事件就傳遞到View部分,也就是Button。
同樣的,Button首先調用的也是dispathTouchEvent()
根據dispathTouchEvent()的返回值:
1.true,已處理,不會向上傳遞;
2.false,未處理,繼續向上傳遞;
繼續到onTouchEvent(),也是根據返回值判斷
1.true,已處理,不會向上傳遞;
2.false,未處理,繼續向下傳遞;
這裏返回false會將事件重新傳遞給ViewGroup(RelativeLayout),調用其onTouch ()方法,根據返回值:
1.true,已處理,不會向上傳遞;
2.false,事件沒有被消費;
需要注意的是,到這裏傳遞事件基本就結束了,如果事件沒有被消費掉,將被Activity外部處理掉,也就不再需要關心了。
最後說明,無論是響應什麼動作,都要先從 ACTION_DOWN事件開始的,如果 ACTION_DOWN沒有被處理,那麼接下來的其他都不會被處理。