android事件攔截處理機制詳解

來源:互聯網
上載者:User

標籤:

 

前段時間剛接觸過Android手機開發,對它的事件傳播機制不是很瞭解,雖然網上也查了相關的資料,但是總覺得理解模模糊糊,似是而非,於是自己就寫個小demo測試了一下。總算搞明白了它的具體機制。寫下自己的結論,分享之,希望對初學android的人有所協助

布局效果:

                      圖1

 

參照先說說具體得到的結論:

1) onInterceptTouchEvent負責對touch事件進行攔截,對於嵌套的view最先執行的是事件攔截方法的是最外層的那個view的onInterceptTouchEvent方法,然後依次執行子視圖的onInterceptTouchEvent,然後在執行子視圖的子視圖的事件攔截方法(當然在這裡假設所有嵌套視圖的onInterceptTouchEvent都會得到執行,讓每個視圖的onInterceptTouchEvent返回false即可)。參照,所以onInterceptTouchEvent執行順序就是A--->B--->C--->D.也就是由父視圖到子視圖傳遞。總之,事件攔截機制是由父視圖開始發起對事件的攔截(出事了老子先上,兒子稍後)。參照當手指觸摸事件時,父視圖A首先發起對該起事件的攔截,如果A攔截失敗,就交給它的子視圖B進行攔截;如果B攔截失敗就交給B的子視圖C再進行攔截..直到某一子視圖對該次事件攔截成功。

2)某一視圖攔截事件成功與否的判斷標識是onInterceptTouchEvent方法的傳回值,當返回true的時候說明攔截成功,返回false的時候說明當前視圖對事件攔截失敗。

3)下面說說攔截成功的情況,假設C視圖對當前touch事件攔截成功。攔截成功意味著此次事件不會再傳遞到D視圖了。所以此時的D視圖的onInterceptTouchEvent就得不到運行(事件沒法到達了,還攔截誰呢?)。事件攔截成功後,緊接著就會對事件進行處理,處理的方法教給onTouchEvent方法處理。此時C視圖攔截成功,那麼緊接著就會執行C視圖的onTouchEvent方法,這是不是就意味著當前touch事件是由C視圖的onTouchEvent方法來處理的呢?這要由C視圖的onTouchEvent方法的傳回值來決定。當C視圖的onTouchEvent返回true的時候,當前事件就由C全權處理,處理的當然是事件的各種action,什麼MotionEvent.ACTION_MOVE,ACTION_UP都交給了C的onTouchEvent方法進行處理。所以此時就可以在C的onTouchEvent方法中進行switch(event.getAction)判斷執行相關邏輯了。如果返回的false,說明C視圖對此事件不做處理或者處理不了,怎麼辦呢?兒子不行老爸來,於是事件就交到了B視圖的onTouchEvent方法中。同樣B對此事件處理與否還是看B的onTouchEvent傳回值,具體的解釋就跟C一樣了,不複多言。

4)在A B C D的onInterceptTouchEvent和onTouchEvent都返回false的情況下,方法執行的順序依次為A.onInterceptTouchEvent-->B.onInterceptTouchEvent-->C.onInterceptTouchEvent-->D.touchEvent(最深的子視圖沒重寫onInterceptTouchEvent)-->C.touchEvent-->B.touchEvent-->A.touchEvent.也就是說攔截事件是父視圖優先有子視圖進行攔截,處理事件是子視圖優先父視圖進行處理。

 總結:onInterceptTouchEvent負責對事件進行攔截,攔截成功後交給最先遇到onTouchEvent返回true的那個view進行處理。


結合事件來源碼分析事件處理機制的話,可以閱讀《從源碼角度解析android事件原理》

下面將要詳細講解上面結論是怎麼得出的,準備分兩部分進行一步步講解。如果上面說的看明白的話,下面的內容就不要看了,因為會很囉嗦。

圖1的布局代碼如下所示:

 

[java] view plain copy  
  1. <com.example.demo.AView 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.     <com.example.demo.BView  
  7.         android:layout_width="match_parent"  
  8.         android:layout_height="match_parent" >  
  9.   
  10.         <com.example.demo.CView  
  11.             android:layout_width="match_parent"  
  12.             android:layout_height="match_parent" >  
  13.   
  14.             <com.example.demo.DView  
  15.                 android:layout_width="match_parent"  
  16.                 android:layout_height="match_parent"  
  17.                 android:text="測試demo" />  
  18.         </com.example.demo.CView>  
  19.     </com.example.demo.BView>  
  20.   
  21. </com.example.demo.AView>  

 

 

其中最後一個D是一個自訂的TextView,與A B C三個View的區別就是D只重寫了onTouchEvent方法,A B C 這三個自訂控制項還重寫了onInterceptEvent方法。

D的代碼如下,A B C代碼基本上除了類名和輸出log不一樣外其餘的都一樣,所以為了減少這裡只貼出其中的一個。

DView的代碼:

 

[java] view plain copy  
  1. public class DView extends TextView{  
  2.     private static String tag = "D";  
  3.     public DView(Context context, AttributeSet attrs, int defStyle) {  
  4.         super(context, attrs, defStyle);  
  5.     }  
  6.   
  7.     public DView(Context context, AttributeSet attrs) {  
  8.         super(context, attrs);  
  9.     }  
  10.   
  11.     public DView(Context context) {  
  12.         super(context);  
  13.     }  
  14.     
  15.     @Override  
  16.     public boolean onTouchEvent(MotionEvent event) {  
  17.         Log.e(tag, "--onTouchEvent--D");      
  18.         return false;  
  19.     }  
  20. }  


AView的代碼和C D的整體差不多,就貼出來一個:

 

 

[java] view plain copy  
  1. public class AView extends RelativeLayout{  
  2.     private static String tag = "A";  
  3.     public AView(Context context) {  
  4.         super(context);  
  5.     }  
  6.   
  7.     public AView(Context context, AttributeSet attrs, int defStyle) {  
  8.         super(context, attrs, defStyle);  
  9.     }  
  10.   
  11.     public AView(Context context, AttributeSet attrs) {  
  12.         super(context, attrs);  
  13.     }  
  14.        
  15.     @Override  
  16.     public boolean onInterceptTouchEvent(MotionEvent ev) {  
  17.         Log.e(tag,"--onInterceptTouchEvent--A");  
  18.         return false;  
  19.     }  
  20.       
  21.     @Override  
  22.     public boolean onTouchEvent(MotionEvent event) {  
  23.         Log.e(tag,"--onTouchEvent---A" );  
  24.         return false;  
  25.     }  
  26. }  

 

 

剛開始的時候重寫的方法全部返回false運行點擊的效果輸出log為:

轉換成為:

 

 

從此圖可以看出,onInterceptTouchEvent事件的執行順序是由父控制項到子控制項,並且優先於自己控制項的onTouchEvent方法執行,onTouchEvent事件執行的順序正好相反由子控制項到父控制項。注意由於此時都返回了false,是沒有哪一個view來處理此次的touch事件的各個ACTION的,這也是為什麼onTouchEvent為什麼會一直傳遞到A的原因。所以ACTION_MOVE和ACTION_UP等事件得不到相應(處理),此種情況下即使你在D的onTouchEvent方法裡面寫了如下代碼,也不會得到執行。

 

[java] view plain copy  
  1. if(event.getAction()==MotionEvent.ACTION_MOVE){  
  2.             Log.e(tag, "--onTouchEvent--*****");  
  3.         }  

 

1)如果A的InterceptTouchEvent返回了true,其餘的仍然返回false,那麼執行輸出的log為:

 

 

轉換成為:

 

 

可以發現此時A攔截了此次Touch事件,事件不再向A的子控制項B C D傳遞。此時所有的action事件比如手指移動事件ACTION_MOVE或者ACTION_UP事件啦等等事件都交給A的onTouchEvent方法去處理(當然這是在onTouchEvent方法返回true的情況下,如果返回false經過測試時不會相應這些action的)。B,C ,D控制項是的事件處理攔截方法和事件處理方法是無法得到執行的。

 

2)只有B的onIntercepteTouchEvent事件返回了true的情況下,列印的log為

 

轉換成為:

 

此時由B攔截了此次Touch事件,並不會向C D子控制項傳遞;同樣的由於onTouchEvent事件返回為false,所以此次事件的event.getAction()的各種action都不會得到處理。

 

4)同理可知,C控制項的onIntercept方法返回了true的情況下,其餘的仍然返回false的情況下,輸出log為

 

轉換成為

下面說說各個view的onTouchEvent返回true的情況

由於onTouchEvent事件是從子控制項到父控制項傳遞的,當D的onTouchEvent返回true的時候,經測試輸出效果如下

轉換成為:

經過測試發現,此時D處理了此次Touch事件的各種action,C B D是的onTouchEvent的沒有得到執行。

同理當C的onTouchEvent方法返回了true的時候,輸出的log如下

轉換成如下:

經過測試發現,此時事件的各個action都在CView的onTouchEvent方法得到了響應,而D的onTouchEvent是不會相應MotionEvent.ACTION_XX的。其餘情況一次類推,就不在囉嗦了。經過一步步的測試得出了文章開頭的結文章有點囉嗦,希望可以對閱讀此文的人有所協助。


結合事件來源碼分析事件處理機制的話,可以閱讀《從源碼角度解析android事件原理》

android事件攔截處理機制詳解

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.