轉載於:http://blog.csdn.net/yuanzeyao/article/details/38025165html
在前一篇文章中,我主要講解了Android源碼中的Touch事件的傳遞過程,如今我想使用一個demo以及一個實例來學習一下Andorid中的Touch事件處理過程。java
在Android系統中,和Touch事件分發和處理緊密相關的三個函數以下:
(1) public boolean dispatchTouchEvent(MotionEvent ev)
(2) public boolean onInterceptTouchEvent(MotionEvent ev)//這個方法在一個事件週期(down,move,up)內只要onInterceptTouchEvent(down/move(up已是最後一次不算)只要攔截了一次)或onTouchEvent(中的ACTION_DOWN)有一個返回true,就不會再走第二次。
(3) public boolean onTouchEvent(MotionEvent event)
這三個方法我在前一篇文章中都對他們的源碼進行了分析:方法1主要是對Touch事件進行分發,方法2主要是對Touch事件進行攔截,方法3是對Touch事件進行處理android
這三個方法主要存在於ViewGroup,View,Activity中,具體狀況以下圖:ide
ViewGroup | View | Activity | |
dispatchTouchEvent | 有 | 有 | 有 |
onInterceptTouchEvent | 有 | 無 | 無 |
onTouchEvent | 有 | 有 | 有 |
下面咱們就使用一個demo來看看這些方法的執行流程:
自定義一個類:MyLayoutFirst.java函數
自定義一個類;MyLayoutSecond.java工具
加入到main_layout.xml中學習
MainActivity中加入onTouchEvent方法this
最後就一個工具類,用來將事件id轉換爲字符串。spa
運行效果如圖:.net
第一中狀況:
MainActivity |
MyLayoutFirst |
MyLayoutSecond |
|
dispatchTouchEvent |
super.dispatchTouchEvent |
super.dispatchTouchEvent |
super.dispatchTouchEvent |
onInterceptTouchEvent |
-- |
super.onInterceptTouchEvent(ev) |
super.onInterceptTouchEvent(ev) |
onTouchEvent |
super.onTouchEvent |
super.onTouchEven |
super.onTouchEvent |
運行結果:
其中藍色部分是MyLayoutSecond.Java ,紅色部分是MyLayoutFirst.java
如今我點擊一下藍色部分:運行結果如圖:
從圖中能夠看出,事件最早被Activity捕獲,而後分發給 MyLayoutFirst,MyLayoutFirst首先調用自身的onInterceptTouchEvent判斷是否將該事件攔截,因爲默認返回是false,因此沒有攔截,從而事件分發給了MyLayoutSecond,MyLayoutSecond一樣經過dispatchTouchEvent分發出去,分發出去以前一樣檢查是否被攔截,默認都是沒有被攔截的,可是因爲MyLayoutSecond是沒有子視圖的,全部最終事件有本身處理,調用自身的onTouchEvent方法,因爲該方法默認返回的是false,因此認爲此事件是沒有被消費掉的,繼續傳遞到了MyLayoutFirst中,一樣也沒有消費這個事件,最終傳遞到了Mainactivity,繼續日後看發現後面的ACTION_MOVE和ACTION_UP並無傳入MyLayoutFirst和MyLayoutSecond,這是由於一旦某一個事件沒有被處理,後面的事件是不會被分發的。因此ACTION_MOVE和ACTION_UP直接被MainActivity處理掉了。
下面再看第二種狀況:
MainActivity |
MyLayoutFirst |
MyLayoutSecond |
|
dispatchTouchEvent |
super.dispatchTouchEvent |
super.dispatchTouchEvent |
super.dispatchTouchEvent |
onInterceptTouchEvent |
-- |
true |
super.onInterceptTouchEvent(ev) |
onTouchEvent |
super.onTouchEvent |
super.onTouchEvent |
super.onTouchEvent |
運行結果以下:
從圖中能夠看出,事件傳遞到了MyLayoutFirst後沒有分發到MyLayoutSecond,直接調用自身的onTouchEvent,因爲返回的是false,致使事件沒有消費,最終傳遞給了MainActivity,
並且後續事件也沒有傳遞到MyLayoutFirst和MyLayoutSecond,直接被MainActivity處理
第三種狀況:
MainActivity |
MyLayoutFirst |
MyLayoutSecond |
|
dispatchTouchEvent |
super.dispatchTouchEvent |
super.dispatchTouchEvent |
super.dispatchTouchEvent |
onInterceptTouchEvent |
-- |
true |
super.onInterceptTouchEvent(ev) |
onTouchEvent |
super.onTouchEvent |
true |
super.onTouchEvent |
運行結果:
和狀況二不一樣的是MyLayoutFirst的onTouchEvent返回了true,也就是說MyLayoutFirst消費了此事件,因此ACTION_DOWN也沒有再傳給MainActivity,而且ACTION_MOVE和ACTION_UP
均傳給了MyLayoutFirst
第四中狀況:
MainActivity |
MyLayoutFirst |
MyLayoutSecond |
|
dispatchTouchEvent |
super.dispatchTouchEvent |
super.dispatchTouchEvent |
super.dispatchTouchEvent |
onInterceptTouchEvent |
-- |
super.onInterceptTouchEvent(ev) |
super.onInterceptTouchEvent(ev) |
onTouchEvent |
super.onTouchEvent |
super.onTouchEven |
true |
運行結果:
發現全部的事件都是傳遞到了MyLayoutSecond後被消費了
第五種狀況:
MainActivity |
MyLayoutFirst |
MyLayoutSecond |
|
dispatchTouchEvent down move up |
super.dispatchTouchEvent super.dispatchTouchEvent super.dispatchTouchEvent |
super.dispatchTouchEvent super.dispatchTouchEvent super.dispatchTouchEvent |
super.dispatchTouchEvent super.dispatchTouchEvent super.dispatchTouchEvent |
onInterceptTouchEvent down move up |
-- |
false true/false false |
super.onInterceptTouchEvent(ev) super.onInterceptTouchEvent(ev) super.onInterceptTouchEvent(ev) |
onTouchEvent down move up |
super.onTouchEvent super.onTouchEvent super.onTouchEvent |
true super.onTouchEven super.onTouchEven |
super.onTouchEvent super.onTouchEvent super.onTouchEvent表示false
|
運行結果:
08-12 10:20:10.592: I/yzy(28806): MainActivity->dispatchTouchEvent->ACTION_DOWN
08-12 10:20:10.602: I/yzy(28806): MyLayoutFirst->dispatchTouchEvent->ACTION_DOWN
08-12 10:20:10.602: W/yzy(28806): MyLayoutFirst->onInterceptTouchEvent->ACTION_DOWN
08-12 10:20:10.612: I/yzy(28806): MyLayoutSecond->dispatchTouchEvent->ACTION_DOWN
08-12 10:20:10.612: W/yzy(28806): MyLayoutSecond->onInterceptTouchEvent->ACTION_DOWN
08-12 10:20:10.622: E/yzy(28806): MyLayoutSecond->MyLayoutSecond->ACTION_DOWN
08-12 10:20:10.622: E/yzy(28806): MyLayoutFirst->onTouchEvent->ACTION_DOWN
08-12 10:20:10.692: I/yzy(28806): MainActivity->dispatchTouchEvent->ACTION_MOVE
08-12 10:20:10.702: I/yzy(28806): MyLayoutFirst->dispatchTouchEvent->ACTION_MOVE
08-12 10:20:10.702: E/yzy(28806): MyLayoutFirst->onTouchEvent->ACTION_MOVE
08-12 10:20:10.702: E/yzy(28806): MainActivity->onTouchEvent->ACTION_MOVE
08-12 10:20:10.712: I/yzy(28806): MainActivity->dispatchTouchEvent->ACTION_MOVE
08-12 10:20:10.712: I/yzy(28806): MyLayoutFirst->dispatchTouchEvent->ACTION_MOVE
08-12 10:20:10.722: E/yzy(28806): MyLayoutFirst->onTouchEvent->ACTION_MOVE
08-12 10:20:10.722: E/yzy(28806): MainActivity->onTouchEvent->ACTION_MOVE
08-12 10:20:10.732: I/yzy(28806): MainActivity->dispatchTouchEvent->ACTION_UP
08-12 10:20:10.732: I/yzy(28806): MyLayoutFirst->dispatchTouchEvent->ACTION_UP
08-12 10:20:10.742: E/yzy(28806): MyLayoutFirst->onTouchEvent->ACTION_UP
08-12 10:20:10.742: E/yzy(28806): MainActivity->onTouchEvent->ACTION_UP
這種狀況代表,只要一個ViewGrounp在onTouchEvent的ACTION_DOWN中消費了事件,那麼不論這個ViewGrounp的onTouchEvent的ACTION_MOVE,ACTION_UP中返回true(消費事件,事件結束)仍是false(事件上傳),事件都會傳到這個ViewGrounp得onTouchEvent中(前提是沒有被在前面就攔截掉),並且這個ViewGrounp得onInterceptTouchEvent也不會再走
第六種狀況:
MainActivity |
MyLayoutFirst |
MyLayoutSecond |
|
dispatchTouchEvent down move up |
super.dispatchTouchEvent super.dispatchTouchEvent super.dispatchTouchEvent |
super.dispatchTouchEvent super.dispatchTouchEvent super.dispatchTouchEvent |
super.dispatchTouchEvent super.dispatchTouchEvent super.dispatchTouchEvent |
onInterceptTouchEvent down move up |
-- |
false false false |
super.onInterceptTouchEvent(ev) super.onInterceptTouchEvent(ev) super.onInterceptTouchEvent(ev) |
onTouchEvent down move up |
super.onTouchEvent super.onTouchEvent super.onTouchEvent |
true true true |
true super.onTouchEvent super.onTouchEvent表示false
|
運行結果:
08-12 11:24:24.992: I/yzy(15159): MainActivity->dispatchTouchEvent->ACTION_DOWN
08-12 11:24:25.002: I/yzy(15159): MyLayoutFirst->dispatchTouchEvent->ACTION_DOWN
08-12 11:24:25.002: W/yzy(15159): MyLayoutFirst->onInterceptTouchEvent->ACTION_DOWN
08-12 11:24:25.012: I/yzy(15159): MyLayoutSecond->dispatchTouchEvent->ACTION_DOWN
08-12 11:24:25.012: W/yzy(15159): MyLayoutSecond->onInterceptTouchEvent->ACTION_DOWN
08-12 11:24:25.022: E/yzy(15159): MyLayoutSecond->MyLayoutSecond->ACTION_DOWN
08-12 11:24:25.032: I/yzy(15159): MainActivity->dispatchTouchEvent->ACTION_MOVE
08-12 11:24:25.032: I/yzy(15159): MyLayoutFirst->dispatchTouchEvent->ACTION_MOVE
08-12 11:24:25.042: W/yzy(15159): MyLayoutFirst->onInterceptTouchEvent->ACTION_MOVE
08-12 11:24:25.042: I/yzy(15159): MyLayoutSecond->dispatchTouchEvent->ACTION_MOVE
08-12 11:24:25.052: E/yzy(15159): MyLayoutSecond->MyLayoutSecond->ACTION_MOVE
08-12 11:24:25.052: E/yzy(15159): MainActivity->onTouchEvent->ACTION_MOVE
08-12 11:24:25.092: I/yzy(15159): MainActivity->dispatchTouchEvent->ACTION_MOVE
08-12 11:24:25.092: I/yzy(15159): MyLayoutFirst->dispatchTouchEvent->ACTION_MOVE
08-12 11:24:25.092: W/yzy(15159): MyLayoutFirst->onInterceptTouchEvent->ACTION_MOVE
08-12 11:24:25.092: I/yzy(15159): MyLayoutSecond->dispatchTouchEvent->ACTION_MOVE
08-12 11:24:25.102: E/yzy(15159): MyLayoutSecond->MyLayoutSecond->ACTION_MOVE
08-12 11:24:25.102: E/yzy(15159): MainActivity->onTouchEvent->ACTION_MOVE
08-12 11:24:25.132: I/yzy(15159): MainActivity->dispatchTouchEvent->ACTION_MOVE
08-12 11:24:25.132: I/yzy(15159): MyLayoutFirst->dispatchTouchEvent->ACTION_MOVE
08-12 11:24:25.132: W/yzy(15159): MyLayoutFirst->onInterceptTouchEvent->ACTION_MOVE
08-12 11:24:25.142: I/yzy(15159): MyLayoutSecond->dispatchTouchEvent->ACTION_MOVE
08-12 11:24:25.142: E/yzy(15159): MyLayoutSecond->MyLayoutSecond->ACTION_MOVE
08-12 11:24:25.142: E/yzy(15159): MainActivity->onTouchEvent->ACTION_MOVE
08-12 11:24:25.152: I/yzy(15159): MainActivity->dispatchTouchEvent->ACTION_UP
08-12 11:24:25.152: I/yzy(15159): MyLayoutFirst->dispatchTouchEvent->ACTION_UP
08-12 11:24:25.162: W/yzy(15159): MyLayoutFirst->onInterceptTouchEvent->ACTION_UP
08-12 11:24:25.162: I/yzy(15159): MyLayoutSecond->dispatchTouchEvent->ACTION_UP
08-12 11:24:25.162: E/yzy(15159): MyLayoutSecond->MyLayoutSecond->ACTION_UP
08-12 11:24:25.172: E/yzy(15159): MainActivity->onTouchEvent->ACTION_UP
當一個ViewGrounp在onTouchEvent的ACTION_DOWN中消費了事件,可是在它的onTouchEvent的ACTION_MOVE,ACTION_UP中返回false的話,雖然事件仍是會傳遞到它的onTouchEvent中,可是它卻會從它本身的onTouchEvent直接上傳回Activity的onTouchEvent中,中間不會通過其餘的ViewGrounp
第七種狀況:
MainActivity |
MyLayoutFirst |
MyLayoutSecond |
|
dispatchTouchEvent down move up |
super.dispatchTouchEvent super.dispatchTouchEvent super.dispatchTouchEvent |
super.dispatchTouchEvent super.dispatchTouchEvent super.dispatchTouchEvent |
super.dispatchTouchEvent super.dispatchTouchEvent super.dispatchTouchEvent |
onInterceptTouchEvent down move up |
-- |
false true false |
super.onInterceptTouchEvent(ev) super.onInterceptTouchEvent(ev) super.onInterceptTouchEvent(ev) |
onTouchEvent down move up |
super.onTouchEvent super.onTouchEvent super.onTouchEvent |
true false false |
true super.onTouchEvent super.onTouchEvent表示false
|
運行結果:
08-12 11:34:54.897: I/yzy(18093): MainActivity->dispatchTouchEvent->ACTION_DOWN
08-12 11:34:54.897: I/yzy(18093): MyLayoutFirst->dispatchTouchEvent->ACTION_DOWN
08-12 11:34:54.917: W/yzy(18093): MyLayoutFirst->onInterceptTouchEvent->ACTION_DOWN
08-12 11:34:54.937: I/yzy(18093): MyLayoutSecond->dispatchTouchEvent->ACTION_DOWN
08-12 11:34:54.947: W/yzy(18093): MyLayoutSecond->onInterceptTouchEvent->ACTION_DOWN
08-12 11:34:54.957: E/yzy(18093): MyLayoutSecond->MyLayoutSecond->ACTION_DOWN
08-12 11:34:54.967: I/yzy(18093): MainActivity->dispatchTouchEvent->ACTION_MOVE
08-12 11:34:54.967: I/yzy(18093): MyLayoutFirst->dispatchTouchEvent->ACTION_MOVE
08-12 11:34:54.977: W/yzy(18093): MyLayoutFirst->onInterceptTouchEvent->ACTION_MOVE
08-12 11:34:54.977: I/yzy(18093): MyLayoutSecond->dispatchTouchEvent->
08-12 11:34:54.977: E/yzy(18093): MyLayoutSecond->MyLayoutSecond->
08-12 11:34:54.977: E/yzy(18093): MainActivity->onTouchEvent->ACTION_MOVE
08-12 11:34:55.017: I/yzy(18093): MainActivity->dispatchTouchEvent->ACTION_MOVE
08-12 11:34:55.027: I/yzy(18093): MyLayoutFirst->dispatchTouchEvent->ACTION_MOVE
08-12 11:34:55.027: E/yzy(18093): MyLayoutFirst->onTouchEvent->ACTION_MOVE
08-12 11:34:55.037: E/yzy(18093): MainActivity->onTouchEvent->ACTION_MOVE
08-12 11:34:55.047: I/yzy(18093): MainActivity->dispatchTouchEvent->ACTION_MOVE
08-12 11:34:55.057: I/yzy(18093): MyLayoutFirst->dispatchTouchEvent->ACTION_MOVE
08-12 11:34:55.067: E/yzy(18093): MyLayoutFirst->onTouchEvent->ACTION_MOVE
08-12 11:34:55.067: E/yzy(18093): MainActivity->onTouchEvent->ACTION_MOVE
08-12 11:34:55.077: I/yzy(18093): MainActivity->dispatchTouchEvent->ACTION_UP
08-12 11:34:55.087: I/yzy(18093): MyLayoutFirst->dispatchTouchEvent->ACTION_UP
08-12 11:34:55.087: E/yzy(18093): MyLayoutFirst->onTouchEvent->ACTION_UP
08-12 11:34:55.097: E/yzy(18093): MainActivity->onTouchEvent->ACTION_UP
MyLayoutSecond的onTouchEvent的ACTION_DOWN中消費了事件,因此事件會默認往他那兒傳遞,可是被MyLayoutFirst的onInterceptTouchEvent在ACTION_MOVE給半路攔截
致使後續操做都被攔截傳遞給MyLayoutFirst的onTouchEvent(但因爲其沒有消費事件,因此會往上傳)
其實還有不少其餘組合方式,你們若是又興趣能夠本身嘗試改變每一個函數的返回值,查看打印結果,這裏我就不一一列舉了。。。。。
最後我會提供一個小demo演示如何解決滑動衝突,背景以下:
一個ViewPager裏面包含兩個Framgent,有一個Fragment裏面有一個HorizontalListView ,如何滑動衝突?
我就貼出關鍵代碼吧
[java] view plain copy
print?
horizontal=(HorizontalListView)view.findViewById(R.id.hscroll);
horizontal.setOnTouchListener(new OnTouchListener()
{
@Override
public boolean onTouch(View arg0, MotionEvent event)
{
if(event.getAction()==MotionEvent.ACTION_DOWN)
{
parent.requestDisallowInterceptTouchEvent(true);
}else if(event.getAction()==MotionEvent.ACTION_UP)
{
parent.requestDisallowInterceptTouchEvent(false);
}
return false;
}
});
加入這段代碼就能夠避免滑動衝突了,至於爲何你們能夠參考個人前之前文章《Android Touch 事件傳遞機制詳解 上》 這兩個demo的例子我均會上傳下載的