Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android_事件紛發

Android_事件紛發

編輯:關於Android編程

關於事件你應該知道的是
當一個事件產生後,他的傳遞過程遵循如下順序Activity > Window > View
事件來源於activity,activity假如你沒有重寫任何關於事件紛發的方法的話,他會把事件傳遞給window,window將事件傳遞給decorView

現在我們來看下假如我們在activity中重寫了dispatchEvent的方法是什麼樣的一個情況.

我們把activity中的dispatchTouchEvent 返回true
這裡寫圖片描述
事件被activity的dispatchTouchEvent消耗掉,所以activity的
onTouchEvent方法得不到響應,我們看下log輸出
這裡寫圖片描述
很明顯的能看出來,log只打印了dispatchTouchEvent中的相關方法,整個事件被dispatchTouchEvent消耗掉,並沒有傳遞到我們的window > decZ喎?/kf/ware/vc/" target="_blank" class="keylink">vclZpZXcgy/nT0M7SvefD5rXEt7W72Lz8vdPK3LK7tb3Kwrz+LMv50tS3tbvYsLTFpbXEteO798rCvP7SssO7yfrQpyw8L3A+DQo8cD7O0sPH1Nqw0WFjdGl2aXR51tC1xGRpc3BhdGNoVG91Y2hFdmVudLe1u9hmYWxzZb+0v7TKx8qyw7TH6b/2LCw8c3Ryb25nPtXi0rLKx87StcTSu7j20snOyrXjLMLpt7O088nxsO/Dpr3itPDSu8/CPC9zdHJvbmc+vs3Kx87SYWN0aXZpdHnW0LXEZGlzcGF0Y2hUb3VjaEV2ZW50t7W72MHLZmFsc2UsxMfDtMrCvP6x6ta+18XKwrz+w7vIy7SmwO0stMvKscrCvP61xLj51LTKx7TTYWN0aXZpdHnAtLXELMjnufvL+7a8sru53LXEu7As1eK49srCvP7S0b6tsrvE3Le1u9jL+7XEuLh2aWV3ICy1scewYWN0aXZpdHm1xG9uVG91Y2hFdmVudCgp0rLO3mxvZ8rks/YsxMfDtMrCvP7ExMDvyKXByz8/Pz88YnIgLz4NCjxpbWcgYWx0PQ=="這裡寫圖片描述" src="/uploadfile/Collfiles/20160401/20160401092456296.png" title="\" />
然後我們看下返回false的log輸出如下圖:
這裡寫圖片描述
log輸出一只執行了activity中的dispatchTouchEvent的相關方法,
TouchEvent並沒有任何輸出,表明activity的onTouchEvent也沒有接受到這個事件,此時我再點擊返回鍵,的onclick依然是失效的,
所以.麻煩大神幫忙解答下這一點,當activity中的dispatchtouchevent返回false,事件的流程是怎麼樣的,???

最後我們讓activity中的dispatchtouchevent 返回super看下
這裡寫圖片描述
然後看下log日志的輸出,以及log 的順序,
這裡寫圖片描述

注意log的順序,dispatchTouchEvent down > onTouchEvent down
dispatchTouchEvent move > onTouchEvent move
dispatchTouchEvent up > onTouchEvent up

面試的時候注意面試官問的問題,和執行順序的問題

然後我們往activity中加入一個linearlayout,我們重寫一下linearlayout的有關事件的三個方法,並打印log看一下,暫時不往linearlayout中加入任何子view,單純的看一下事件從activity傳遞到viewgroup的效果.

首先我們在書寫一個TESTLinearlayout,如下

public class AAATestLinearlayout extends LinearLayout {
    private static final String TAG = "AAATestLinearlayout";

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

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

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

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Logger.e(TAG, TAG + ">>>>dispatchTouchEvent.ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Logger.d(TAG, TAG + ">>>>dispatchTouchEvent.ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Logger.w(TAG, TAG + ">>>>dispatchTouchEvent.ACTION_UP");
                break;
        }

//        return true;
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Logger.e(TAG, TAG + ">>>>onInterceptTouchEvent.ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Logger.d(TAG, TAG + ">>>>onInterceptTouchEvent.ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Logger.w(TAG, TAG + ">>>>onInterceptTouchEvent.ACTION_UP");
                break;
        }

//        return true;
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Logger.e(TAG, TAG + ">>>>onTouchEvent.ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Logger.d(TAG, TAG + ">>>>onTouchEvent.ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Logger.w(TAG, TAG + ">>>>onTouchEvent.ACTION_UP");
                break;
        }

        return super.onTouchEvent(event);
    }

}

我們就先默認的讓測試的linearlayout全部返回super值.

看下事件傳遞的過程從activity > window > decorView > 我們自己的linearlayout;
這裡寫圖片描述

並且我們在linearlayout中的構造中設置了額外的onTouchLinstener,
我們看下的結果;
這裡寫圖片描述
這裡寫圖片描述

這裡簡答描述一下,我們往activity中加入了一個linearlayout.並且在構造中給linearlayoutset了一個touchlistener.
我們從log可以看到,事件從activity中開始傳遞,然後我們在linearlayout中有關事件的方法全部返回super.
其中關於onInterceptTouchEvent
我想說兩句,這句話的返回值影響的是viewgroup容器中子view的事件傳遞,並不會對當前的viewgroup的onTouchEvent或者set 的touchlistener有影響,我們從log可以看出來,linearlayout的 onTouchEvent.down 和 touchliste的down均執行了

假如onInterceptTouchEvent的值返回的是super的話,我們看viewgroup的源碼可以知道
默認是false,也就是不攔截…重要的是不攔截….

    * appear here.
     * 
     *
     * @param ev The motion event being dispatched down the hierarchy.
     * @return Return true to steal motion events from the children and have
     * them dispatched to this ViewGroup through onTouchEvent().
     * The current target will receive an ACTION_CANCEL event, and no further
     * messages will be delivered here.
     */
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return false;
    }

這是viewgroup的源碼,和Android藝術探索第143頁第六條說的完全吻合,
還有一篇博客,應該是比較經典的,其中對onInterceptTouchEvent的解釋如下;
這裡寫圖片描述

這裡博客博主說是返回super的話默認被攔截,並把攔截的事件交給當前view,處理,
我們這裡的當前view就是我們的linearlayoutlayout 從log看確實執行了onTouchEvent.但是這個onTouchEvent並不是因為返回了super他沒有攔截而執行了.因為筆者試著返回true false,super,對我們設置的touchlistener和onTouchEvent的down事件沒有任何影響,

所以這塊我也迷茫了半天,看了書本和咨詢了群裡的nil大概猜測一下可能是博主理解有出入或者筆誤,再次留下博客的地址:請大神批閱和校正一下原文鏈接如下Android編程下的事件紛發

接著說我們的場景,目前我們linearlayout中的事件處理方法均沒有對事件做處理,這樣我們linearlayout中的子view比如我們的返回按鈕確實能接收到事件,然後點擊返回箭頭,activity關閉,此事第一個場景走完.

第二個場景,我們把我們的liearlayout中的dispatchTouchEvent返回true,
我們猜想是這樣的,如果返回true,事件就在當前的方法中終止了也就是在liearlayout中終止,所以其他的方法根本不會接收到這個事件,所以看下我們執行的log輸出,
這裡寫圖片描述

這裡寫圖片描述

這裡以為linearlayout中dispatchonTouchEvent返回了true,事件在這裡終止了,所以我們的返回箭頭就接收不到事件,於是我們的返回按鈕就失效了.

第二個場景,我們讓linearlayout的dispatchonTouchEvent返回false,那麼這個觸摸事件將是一個怎麼樣的過程呢?

dispatchonTouchEvent.返回false,事件要被來自哪裡,就要被返回哪裡,假如我們的linearlayout還有父view ,那麼這個事件將返回給父view的onTouchEvent事件處理,如果來自activity,那麼將被activity的onTouchEvent處理,看下我們的log輸出;

這裡寫圖片描述

![這裡寫圖片描述](http://img.blog.csdn.net/20160331173347685)

這裡寫圖片描述

當我們點擊我們的返回箭頭的時候,因為事件從liearlayout中返回給了activity消費,所以子控件沒法接收到事件,所以點擊返回的箭頭也無法生效;

第三個場景,linearlayout中的onInterceptTouchEvent返回true,其他返回super,猜想,攔截事件返回true,那麼事件不會傳遞給子view,
返回按鈕不會生效.因為我們其他的方法都是返回到 super,所以事件在onTouchEvent中返回了給其父view 或者activity,由於activity中的onTouchEvent也返回到 super,所以事件消失,..具體看log輸出的過程和解釋
這裡寫圖片描述

這裡寫圖片描述

這裡寫圖片描述

因為事件也在activity中,並沒有傳遞給子view 所以返回按鈕失效

下一個場景,讓我們的liearlayout中的onInterceptTouchEvent返回false,不攔截,那麼事件將會傳遞給子view,子view在去調用自己的dispatch方法去紛發,這樣事件就能被返回箭頭接受,可以正常關閉activity

我們看下log輸出,
這裡寫圖片描述

這裡寫圖片描述

由於onInterceptTouchevent返回了false,所以事件執行完他裡面的方法後就把事件傳遞給了子view,於是事件就從發源地activity 和linearlayout中的 dispatch 和 intercept 起作用,並沒有onTouchEvent的事情了,具體細節看log輸出描述,然後由於事件傳遞給了子view 所以 返回箭頭生效,這個方法返回false和返回super產生的效果是一模一樣的,這裡就不在截圖了有興趣的可以輸出一下

到此為止我們activity中只有一個viewgroup的場景基本分析完畢了,然後我們想liearlayout中添加一個textview如下圖

這裡寫圖片描述

因為我們這裡加入的是最小單位的view就是view不能再添加額外的內容,我們手指觸摸屏幕事件傳遞過程,有activity 到 liearlayout 在到view 在返回 linearlayout ,返回activity 直到消失,具體過程如下;

這裡寫圖片描述

這裡寫圖片描述

這裡寫圖片描述

再來一個場景,這次我們讓childview中的dispatch 事件返回false,
筆者本來也是對這個傳遞有點模糊的,今天博客寫到這裡我都能猜到打印結果了,由於textviewdispatch返回了false ,所以事件執行完dispatch down後直接把事假返回給父view linearlayout的onTouchEvent,由於onTouchEvent設置了touchlistener 所以後執行,然後就是父view也返回了super,所以事件傳遞給activity的onTouchEvent 由於activity的onTouchEvent也返回了super.所以事件消失,最後在activity中執行 move 和 up

然後我們看下打印結果;

這裡寫圖片描述

這裡寫圖片描述

寫到這裡,理解的事件傳遞在腦海裡的模糊場景已經有點透明了,還需要更多的實踐,文中可能有理解不到位的也請大神批正,到此我理解的事件傳遞在viewgroup 和view中全部結束,也感謝群裡nil的指點謝謝!

如果你看完還是對這個過程不是很理解,請自己模擬場景打印log,因為我感覺沒有在比筆者更笨出身更貧寒的了,當你模擬看log有點想吐甚至能猜到不同的返回值會是什麼樣的傳遞場景,那麼你對事件傳遞的過程相比之前你的理解肯定有恍然大悟的!謝謝….

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