Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android事件攔截處理機制詳解

android事件攔截處理機制詳解

編輯:關於Android編程

前段時間剛接觸過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進行處理。

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

 

 

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

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

DView的代碼:

 

public class DView extends TextView{
    private static String tag = D;
	public DView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	public DView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public DView(Context context) {
		super(context);
	}
  
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		Log.e(tag, --onTouchEvent--D);	
		return false;
	}
}

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

 

 

public class AView extends RelativeLayout{
    private static String tag = A;
	public AView(Context context) {
		super(context);
	}

	public AView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	public AView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}
	 
	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		Log.e(tag,--onInterceptTouchEvent--A);
		return false;
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		Log.e(tag,--onTouchEvent---A );
		return false;
	}
}

 

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

\

轉換成效果圖為:

\

 

 

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

 

if(event.getAction()==MotionEvent.ACTION_MOVE){
			Log.e(tag, --onTouchEvent--*****);
		}

 

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的。其余情況一次類推,就不在啰嗦了。經過一步步的測試得出了文章開頭的結文章有點啰嗦,希望可以對閱讀此文的人有所幫助。




  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved