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

Android圖解淺析事件攔截機制

編輯:關於Android編程

當Android系統捕獲到用戶的各種輸入事件後,如何准確的傳遞給真正的需要這個事件的控件?Android提供了一整套完善的事件傳遞、處理機制,來幫助開發者完成准確的事件分配與處理,這裡我就不分析源碼了,簡單點,圖形化分發過程,便於理解。

當我們點擊一個按鈕時,通常會產生兩個或者三個事件---按下、滑動(可能無)、抬起。Android為觸摸事件封裝了一個類----MotionEvent,其中假如我們重寫一個view的onTouchEvent事件中的參數就是一個MotionEvent。由於Android的View結構是樹形結構,也就是說,View可以放在ViewGroup裡面,通過不同的組合來實現不同的樣式。View可以放在一個ViewGroip,而這個ViewGroup又放在另一個ViewGroup裡面,甚至還有可能繼續嵌套。可能同一個事件,子View和ViewGroup都有可能想要進行處理,因此怎麼樣去“分發“和“攔截”的問題就產生了。

假設有這麼一個View,一個ViewGroupA,裡面嵌套了另一個ViewGroupB,而ViewGroupB裡面有一個view。整體的布局結構如下:

\

布局文件如下:

 



    

        

            
        
    

 

整體的Activity包含3個自定義的View,項目結構是MyView、MyViewGroupB、MyViewGroupA。所以整體Touch事件的主角是View和ViewGroup,而與View相關的Touch事件有2個dispatchTouchEvent和onTouchEvent;與ViewGroup相關的Touch事件有3個dispatchTouchEvent,onInterceptTouchEvent,onTouchEvent。所以我們在定義好View和ViewGroup後,讓其分別是實現這些方法。

代碼如下:

MyView.java

 

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

public class MyView extends View {
	private String Tag = "MyView";

	public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
	}

	public MyView(Context context, AttributeSet attrs) {
		super(context, attrs);
		Log.d(Tag, "----->MyView");
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		Log.e(Tag, "----->onTouchEvent");
		return super.onTouchEvent(event);
	}

	@Override
	public boolean dispatchTouchEvent(MotionEvent event) {
		Log.e(Tag, "----->dispatchTouchEvent");
		return super.dispatchTouchEvent(event);

	}

}
MyViewGroupA.java
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.widget.LinearLayout;

public class MyViewGroupA extends LinearLayout {
	private String Tag = "MyViewGroupA";

	public MyViewGroupA(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		// TODO 自動生成的構造函數存根
	}

	public MyViewGroupA(Context context, AttributeSet attrs) {
		super(context, attrs);
		Log.d(Tag, "----->MyViewGroupA");
	}

	@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {
		Log.e(Tag, "----->dispatchTouchEvent");
		return super.dispatchTouchEvent(ev);
	}

	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		Log.e(Tag, "----->onInterceptTouchEvent");
		return super.onInterceptTouchEvent(ev);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		Log.e(Tag, "----->onTouchEvent");
		return super.onTouchEvent(event);
	}

}
MyViewGroupB和A一樣,就不貼了。

 

其中上面事件的傳遞的返回值是這樣的,如果返回true,表示該View(ViewGroup)攔截了,不繼續往下分發事件了,如果返回false,表示不攔截,繼續往下分發。默認的調用父方法super.xxx是表示不攔截的意思。

下面就開始來驗證吧。

運行我們的項目,先看看我們3個view的加載情況吧:

\

可以看出是由外到內加載的。

好了,開始touch事件吧,現在我們先點擊最外層粉紅的ViewGroupA,觀察Log輸出:

\

然後點擊藍色區域的ViewGroupB,再觀察Log輸出:

\
最後點擊MyView觀察輸出

\

由此,我們可以大致的繪制出如下圖所示的這樣的一個圖解流程。

\

現在假如我們修改MyViewGroupA中的onInterceptTouchEvent()事件,將其返回值改為True,點擊任意一層view,現在我們再看log輸出:

\

可以看出只有A的3個事件進行了處理,由此事件被A攔截了。流程圖如下所示:

\

同理,將A的返回值改回來,我們修改MyViewGroupB的onInterceptTouchEvent()方法,也返回true,然後點擊MyView或者MyViewGroupB,試試。Log輸出如下:

\

也就是事件只是分發到了MyViewGroupB,沒有到MyView,整個流程圖如下所示:

\

最後,假如底層的MyView想處理呢,相應的我們只用修改下onTouchEvent()的返回值就好,將其改為返回true.然後點擊MyView看看log輸出。

\

流程圖是這樣的:

\

 

 

 

好了,文章到此結束,先簡單的對分發和攔截有個大致的了解,但事件分發機制還沒完全分析完,等待下一篇再來分析。

 

最後,如果對文章有什麼疑惑,歡迎指出,共同進步!

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