Android 時間攔截機制

來源:互聯網
上載者:User

Android 時間攔截機制

對於Android事件攔截機制,相信對於大多數Android初學者是一個抓耳撓腮難於理解的問題。其實理解這個問題並不困難。

首先,你的明白事件攔截機制到底是怎麼一回事?這裡說的事件攔截機制,指的是對觸摸事件的攔截機制。那何為觸摸事件?所謂的觸摸事件,就是指系統捕獲的觸控螢幕幕所產生的事件。當我們點擊按鈕時候,此時其實就產生了三個事件。按鈕按下,這是事件之一;如果你不小心滑動了一點兒,這是事件之二;如果你抬起,這是事件之三。Android為我們這個觸摸事件封裝了一個類——MotionEvent。在OnTouchEvent事件中,能夠非常方便的監聽這三個事件。

既然,能夠監聽這個觸摸事件,那麼何來事件攔截之說了。那麼,接下來,請同學們設想這樣一個情境好嗎?一個View放在一個ViewGroup裡面,這個父ViewGroup控制項又放在另外一個VIewGroup裡面,甚至還可以繼續嵌套,這樣子子孫孫無窮盡彥。那麼問題來了呀?可觸摸事件這裡只有一個呀,我到底把他給誰。爹爹ViewGroup與子View都想處理這個觸摸事件了,於是"事件攔截"這個很霸氣的名字就應運而生。

要理解這個事件攔截機制,我這裡需要置身於一個設身處地的情境。就好比你所在一個公司,有一個CEO,CEO下面有總監,總監下面是經理,經理下面有個苦逼的你。此時,來了一項任務以後,CEO把他分配總監,總監分配給經理,經理就把他交給你。這樣任務上傳下達的流程,就與事件分發與攔截流程蠻像了。

為了事件更好的理解這個案例,我這裡就用控制項結構類比這樣的組織圖,來較深入的講解事件攔截機制。

  我們看一下這個控制項UI架構圖:

怎麼在判斷是父容器與子控制項發生了事件攔截,在父容器(ViewGroup)中監聽OnTouchEvent()事件,DispatchEvent()事件與OninterceptEvent()事件,在子View監聽OnTouchEvent()事件與DispatchEvent()事件。怎麼看這些事件進行調用了,我們在每個事件列印相應的日誌,就ok了。好好好,有了這樣大體一個思路,我們就可以上原始碼了。

子View原始碼如下:

public class MyView extends View {    public MyView(Context context) {        super(context);    }    public MyView(Context context, AttributeSet attrs) {        super(context, attrs);    }    public MyView(Context context, AttributeSet attrs,                  int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        Log.d("zcw", "View onTouchEvent" + event.getAction());        return super.onTouchEvent(event);    }    @Override    public boolean dispatchTouchEvent(MotionEvent event) {        Log.d("zcw", "View dispatchTouchEvent" + event.getAction());        return super.dispatchTouchEvent(event);    }}

父ViewGroup原始碼如下:

public class MyViewGroupC extends LinearLayout {    public MyViewGroupC(Context context) {        super(context);    }    public MyViewGroupC(Context context, AttributeSet attrs) {        super(context, attrs);    }    public MyViewGroupC(Context context, AttributeSet attrs,                        int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        Log.d("zcw", "ViewGroupC dispatchTouchEvent" + ev.getAction());        return super.dispatchTouchEvent(ev);    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        Log.d("zcw", "ViewGroupC onInterceptTouchEvent" + ev.getAction());        return super.onInterceptTouchEvent(ev);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        Log.d("zcw", "ViewGroupC onTouchEvent" + event.getAction());        return super.onTouchEvent(event);    }}

祖ViewGroup的原始碼如下:

public class MyViewGroupB extends LinearLayout {    public MyViewGroupB(Context context) {        super(context);    }    public MyViewGroupB(Context context, AttributeSet attrs) {        super(context, attrs);    }    public MyViewGroupB(Context context, AttributeSet attrs,                        int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        Log.d("zcw", "ViewGroupB dispatchTouchEvent" + ev.getAction());        return super.dispatchTouchEvent(ev);    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        Log.d("zcw", "ViewGroupB onInterceptTouchEvent" + ev.getAction());        return super.onInterceptTouchEvent(ev);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        Log.d("zcw", "ViewGroupB onTouchEvent" + event.getAction());        return super.onTouchEvent(event);    }}

曾祖ViewGroup控制項的原始碼如下:

public class MyViewGroupA extends LinearLayout {    public MyViewGroupA(Context context) {        super(context);    }    public MyViewGroupA(Context context, AttributeSet attrs) {        super(context, attrs);    }    public MyViewGroupA(Context context, AttributeSet attrs,                        int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        Log.d("zcw", "ViewGroupA dispatchTouchEvent" + ev.getAction());        return super.dispatchTouchEvent(ev);    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        Log.d("zcw", "ViewGroupA onInterceptTouchEvent" + ev.getAction());        return super.onInterceptTouchEvent(ev);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        Log.d("zcw", "ViewGroupA onTouchEvent" + event.getAction());        return super.onTouchEvent(event);    }}

我們在每個要監聽事件裡面都埋下了點。

我們運行程式,看每個控制項的事件執行的先後順序:

 

我們觸摸子View時候,發現越頂層父控制項控制項DispatchEvent,onInterceptTouchEvent事件越先執行。當裡層OnTouchEvent方法執行完全,然後由裡到外執行OnTouchEvent方法。執行流程圖是這樣的:

我們稍微修改一下子控制項的代碼,在onTouchEvent方法中返回true的話,此時運行效果就是這樣的了。

 

我們,就可以得出來這樣的結論,如果是return true 以後,就是把該事件進行截取,要不向下傳遞的事件。這就是android事件攔截的本質。

return false——事件放任自流,該傳遞的就進行傳遞,return true——自己做了,不麻煩別人了,事件截獲,不進行傳遞了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.