Android Touch消息傳遞機制探究分析

在Android中,消息的傳遞控制主要是經過兩個方法共同配合使用來對用戶的觸摸消息進行分發的,下面就來看看這兩個方法;併發

  1. onInterceptTouchEvent:此方法定義於ViewGroup中,顧名思義,這個方法是用於ViewGroup攔截(intercept)觸摸消息的;
  2. onTouchEvent:此方法定義於View中,用於處理用戶的觸摸事件;

下面來看這兩個方法的定義原型;ide

public boolean onInterceptTouchEvent(MotionEvent ev);
public boolean onTouchEvent(MotionEvent event);

這兩個方法的一個共同點就是都有一個參數MotionEvent用於獲取觸摸事件的具體信息(好比按下,移動等等消息形態)和函數返回值(用於控制不一樣場合的觸摸處理);函數

簡單說一下MotionEvent,它包含了用戶觸摸消息的類型,經常使用的幾種觸摸消息類型爲:ACTION_DOWN,ACTION_MOVE,ACTION_UP,ACTION_CANCEL, 分別表示觸摸按下,移動,結束的狀態;這幾種消息類型不是併發產生的,而是如同觸摸發生的次序同樣有序產生的,DOWN->MOVE->UP/CANCEL;spa

下邊經過一個例子來研究,分別自定義一個簡單的ViewGroup和View,用於跟蹤onTouchEvent和onInterceptTouchEvent的執行;3d

LLinearLayoutcode

public class LLinearLayout extends LinearLayout {

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

    public LLinearLayout(Context context) {
        super(context);
    }

    private float lastY;

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        String tag = "onInterceptTouchEvent";
        Log.w(tag, "" + super.onInterceptTouchEvent(ev));
        switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            Log.w(tag, "ACTION_DOWN");
            lastY = ev.getX();
            break;
        case MotionEvent.ACTION_MOVE:
            Log.w(tag, "ACTION_MOVE");
            if (ev.getX() - lastY > 20) {
                Log.w(tag, "ACTION_MOVE>20");
                return true;
            }
            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            Log.w(tag, "ACTION_UP");
            break;
        }
        return false;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.w("onTouchEvent", "" + super.onTouchEvent(event));
        return false;
    }
}

LViewxml

public class LView extends ImageView {

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

    public LView(Context context) {
        super(context);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        String tag = "LView.onTouchEvent";
        Log.e(tag, "" + super.onTouchEvent(event));
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            Log.e(tag, "ACTION_DOWN");
            break;
        case MotionEvent.ACTION_MOVE:
            Log.e(tag, "ACTION_MOVE");
            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            Log.e(tag, "ACTION_UP");
            break;
        }
        return false;
    }
}

在xml文件中將LView加入LLinearLayout中,經過一系列更改來一控究竟;blog

step1:事件

經過上面的Log信息,能夠看出,觸摸事件先被LLinearLayout攔截到(onInterceptTouchEvent),在這個Demo中,該方法返回值爲false,接着就將Touch事件傳遞給LView,LView的onTouchEvent響應了這次觸摸事件,而且也返回false;而後Touch事件再傳遞給LLinearLayout的onTouchEvent進行處理;get

從上面咱們能夠簡單的看出,Touch事件先被LLinearLayout攔截到,而後傳遞給LView,LView執行onTouchEvent處理邏輯;而後LLinearLayout再執行本身的onTouchEvent處理邏輯;@1

step2:將上面LLinearLayout的onInterceptTouchEvent方法返回值改成true,再次運行程序;

 

相比上面的Log信息,能夠看到消息沒有傳遞到LView;到這裏,應該能夠得出一個小小的結論了吧;

ViewGroup裏面的onInterceptTouchEvent返回值,返回true表示攔截Touch事件,再也不將Touch事件傳遞給ViewGroup裏面的子View;

step3: 回到step1,將LView中onTouchEvent返回值改成true,再次運行程序,手指從屏幕右滑到左;

從Log信息中,能夠看出,LView的onTouchEvent返回值爲true時,LView的觸摸事件從DOWN傳遞到了MOVE,再傳遞到UP;固然,整個過程都是先由LLinearLayout的onInterceptTouchEvent先接收到Touch事件,在這裏,並無攔截Touch事件,而是將Touch事件傳遞給子View;細心的朋友可能會發現,在這裏,並無執行到LLinearLayout的onTouchEvent方法,why?實際上是由於LView的onTouchEvent事件返回了true,表示處理消耗了此事件,再也不繼續傳遞,也就不執行到LLinearLayout的onTouchEvent方法;

結論:View的onTouchEvent返回值表示是否將繼續傳遞Touch事件,好比若是返回true,觸摸形態將會從DOWN傳遞到MOVE再到UP(這裏這個說法其實不嚴謹,這裏指的是整個onTouchEvent方法返回值都是true,而沒有分段返回,好比在MOVE形態時返回了false);

step4:繼續step3,運行程序,手指從屏幕左滑到右;

在LLinearLayout的onInterceptTouchEvent中,若是MOVE消息向右滑動距離大於20,則將攔截Touch事件,因此,在事件被攔截後,將不會再像step3中,MOVE消息會在LView的onTouchEvent中不斷傳遞,而是被中斷,觸摸形態變爲到ACTION_UP即手指擡起(其實這裏這樣說是不對的,準確的說是觸摸形態變爲ACTION_CANCEL,由於我將UP和CANCEL處理爲一類,因此如上圖,打印出來的Log信息爲ACTION_UP,實際上它本質是ACTION_CANCEL);而後因爲ACTION_MOVE被攔截,因此在手指MOVE的時候LLinearLayout的onTouchEevent不斷被調用;

 

結尾總結:

ViewGroup裏的onInterceptTouchEvent默認值是false,只有當返回值是false的時候,Touch事件才傳給子View,而後調用到子View的onTouchEvent;返回值爲true的時候,將攔截用戶Touch事件,子View則捕獲不到觸摸事件;

View的onTouchEvent方法,當返回值爲true的時候,事件將繼續往下傳遞,由ACTION_DOWN傳遞到ACTION_MOVE再到ACTION_UP,反之若是返回值爲false,則只會捕獲到MotionEvent的ACTION_DOWN形態;

相關文章
相關標籤/搜索