編輯:關於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輸出。

流程圖是這樣的:

好了,文章到此結束,先簡單的對分發和攔截有個大致的了解,但事件分發機制還沒完全分析完,等待下一篇再來分析。
最後,如果對文章有什麼疑惑,歡迎指出,共同進步!
Android實現界面左右滑動切換功能
相信大家一定都使用過手機QQ和微信之類的軟件,當我們使用時不難發現其界面的切換不僅可以通過點擊頁標簽來實現,還可以通過左右滑動來實現的,耗子君剛開始學Android時就覺
多媒體播放器02視頻播放器
實現一個播放器裡的全屏播放功能視頻播放器的核心是:VideoView使用AndroidStudio設置Activity的全橫屏會出現閃退解決方法:把運行類的繼承改成Act
android中反射技術使用實例
在計算機科學領域,反射是指一類應用,它們能夠自描述和自控制。也就是說,這類應用通過采用某種機制來實現對自己行為的描述(self-representation)和監測(ex
小米電視2s和小米電視2區別
小米電視2s定價在2999很大程度上是小米電視2s功能的刪減,其中大家最為關注的是砍掉了3D功能,3d功能可能不是每個人都需要,但是有總比沒有要好嗎?你說對