Android Touch事件傳遞機制 二:單純的(僞生命週期) 這個清楚一點

轉載於: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函數

 

[java]  view plain  copy
 
 print?
  1. public class MyLayoutFirst extends LinearLayout  
  2. {  
  3.   private static final String TAG = "MyLayoutFirst";  
  4.   public MyLayoutFirst(Context context, AttributeSet attrs)  
  5.   {  
  6.     super(context, attrs);  
  7.   }  
  8.     
  9.   @Override  
  10.   public boolean onInterceptTouchEvent(MotionEvent ev)  
  11.   {  
  12.     Log.w("yzy", "MyLayoutFirst->onInterceptTouchEvent->"+MyUtils.getActionName(ev));  
  13.     return super.onInterceptTouchEvent(ev);  
  14.   }  
  15.     
  16.   @Override  
  17.   public boolean onTouchEvent(MotionEvent event)  
  18.   {  
  19.     Log.e("yzy", "MyLayoutFirst->onTouchEvent->"+MyUtils.getActionName(event));  
  20.     return super.onTouchEvent(event);  
  21.   }  
  22.     
  23.   @Override  
  24.   public boolean dispatchTouchEvent(MotionEvent ev)  
  25.   {  
  26.     Log.i("yzy", "MyLayoutFirst->dispatchTouchEvent->"+MyUtils.getActionName(ev));  
  27.     return super.dispatchTouchEvent(ev);  
  28.   }  
  29.     
  30. }  


自定義一個類;MyLayoutSecond.java工具

 

 

[java]  view plain  copy
 
 print?
  1. public class MyLayoutSecond extends LinearLayout  
  2. {  
  3.   private static final String TAG = "MyLayoutSecond";  
  4.   public MyLayoutSecond(Context context, AttributeSet attrs)  
  5.   {  
  6.     super(context, attrs);  
  7.   }  
  8.     
  9.   @Override  
  10.   public boolean onTouchEvent(MotionEvent event)  
  11.   {  
  12.     Log.e("yzy", "MyLayoutSecond->MyLayoutSecond->"+MyUtils.getActionName(event));  
  13.     return super.onTouchEvent(event);  
  14.   }  
  15.     
  16.   @Override  
  17.   public boolean onInterceptTouchEvent(MotionEvent ev)  
  18.   {  
  19.     Log.w("yzy", "MyLayoutSecond->onInterceptTouchEvent->"+MyUtils.getActionName(ev));  
  20.     return super.onInterceptTouchEvent(ev);  
  21.   }  
  22.     
  23.   @Override  
  24.   public boolean dispatchTouchEvent(MotionEvent ev)  
  25.   {  
  26.     Log.i("yzy", "MyLayoutSecond->dispatchTouchEvent->"+MyUtils.getActionName(ev));  
  27.     return super.dispatchTouchEvent(ev);  
  28.   }  
  29.   
  30.    
  31. }  


加入到main_layout.xml中學習

 

 

[html]  view plain  copy
 
 print?
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.    >  
  6.   
  7.     <com.event.demo.MyLayoutFirst   
  8.         android:id="@+id/layout_first"  
  9.         android:layout_width="match_parent"  
  10.         android:layout_height="match_parent"  
  11.         android:background="#FF0000"  
  12.         >  
  13.         <com.event.demo.MyLayoutSecond  
  14.             android:id="@+id/layout_second"  
  15.             android:layout_width="320dip"  
  16.             android:layout_height="120dip"  
  17.             android:layout_gravity="center"  
  18.             android:background="#0000FF"  
  19.         >  
  20.           
  21.     </com.event.demo.MyLayoutSecond>  
  22.     </com.event.demo.MyLayoutFirst>  
  23.   
  24. </RelativeLayout>  


MainActivity中加入onTouchEvent方法this

 

 

[java]  view plain  copy
 
 print?
  1. public class MainActivity extends Activity  
  2. {  
  3.   
  4.   @Override  
  5.   protected void onCreate(Bundle savedInstanceState)  
  6.   {  
  7.     super.onCreate(savedInstanceState);  
  8.     setContentView(R.layout.activity_main);  
  9.   }  
  10.   
  11.   @Override  
  12.   public boolean onCreateOptionsMenu(Menu menu)  
  13.   {  
  14.     // Inflate the menu; this adds items to the action bar if it is present.  
  15.     getMenuInflater().inflate(R.menu.main, menu);  
  16.     return true;  
  17.   }  
  18.     
  19.   @Override  
  20.   public boolean dispatchTouchEvent(MotionEvent ev)  
  21.   {  
  22.     Log.i("yzy", "MainActivity->dispatchTouchEvent->"+MyUtils.getActionName(ev));  
  23.     return super.dispatchTouchEvent(ev);  
  24.   }  
  25.     
  26.   @Override  
  27.   public boolean onTouchEvent(MotionEvent event)  
  28.   {  
  29.     Log.e("yzy", "MainActivity->onTouchEvent->"+MyUtils.getActionName(event));  
  30.     return super.onTouchEvent(event);  
  31.   }  
  32. }  


最後就一個工具類,用來將事件id轉換爲字符串。spa

 

 

[java]  view plain  copy
 
 print?
  1. public class MyUtils  
  2. {  
  3.   private static final String TAG = "MyUtils";  
  4.   public static String getActionName(MotionEvent event)  
  5.   {  
  6.     String name="";  
  7.     switch(event.getAction())  
  8.     {  
  9.       case MotionEvent.ACTION_DOWN:  
  10.         name="ACTION_DOWN";  
  11.         break;  
  12.       case MotionEvent.ACTION_MOVE:  
  13.         name="ACTION_MOVE";  
  14.         break;  
  15.       case MotionEvent.ACTION_UP:  
  16.         name="ACTION_UP";  
  17.         break;  
  18.     }  
  19.     return name;  
  20.   }  
  21. }  


運行效果如圖:.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的例子我均會上傳下載的

相關文章
相關標籤/搜索