1. 程式人生 > >Android中Activity觸控事件傳遞原始碼學習

Android中Activity觸控事件傳遞原始碼學習

Activity中的觸控事件傳遞對應兩個方法:dispatchTouchEvent和onTouchEvent。分別是分發和消費。
先來看分發。

 /**
     * Called to process touch screen events.  You can override this to
     * intercept all touch screen events before they are dispatched to the
     * window.  Be sure to call this implementation for touch screen events
     * that should be handled normally.
     * @param
ev The touch screen event. * @return boolean Return true if this event was consumed. */
public boolean dispatchTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { onUserInteraction(); } if (getWindow().superDispatchTouchEvent(ev)) { return
true; } return onTouchEvent(ev); }

第一個就有點看懵了。不過還是一步步看下去吧。先看註釋!我英語不是很好,谷歌翻譯了一下,自己也理解了一些,註釋的翻譯大概是:這個方法的是用來處理螢幕的觸控事件的。你可以重寫這個方法在分發到window之前去攔截圖幕的觸控事件。最好要用正常的方式來處理這些觸控事件。我的理解就是在觸控我們的應用時,首先是觸控事件先到達Activity中,重寫這個方法可以控制觸控事件的是否分發到Activity介面中的ViewGroup、View中。
這裡說下Android中Window的概念。先來google翻譯下Window這個抽象類註釋中的說明:抽象基類的頂級視窗外觀和行為策略。 應該使用此類的例項作為新增到視窗管理器的頂級檢視。 它提供標準的UI策略,如背景,標題區域,預設金鑰處理等。
我的理解是Window是一種容器,用來裝Activity、Dialog等檢視。我們設定一個應用的主題就相當於給Window設定了一些基礎的背景、標題區域等因此能看到一個應用中的Activity等檢視有一致的基礎樣式。

接著看程式碼,一開始就是一個判斷,當觸控事件是ACTION_DOWN時,呼叫了onUserInteraction()方法。找到方法的位置,發現是一個空方法,上面有一大段註釋。程式碼如下:

/**
     * Called whenever a key, touch, or trackball event is dispatched to the
     * activity.  Implement this method if you wish to know that the user has
     * interacted with the device in some way while your activity is running.
     * This callback and {@link #onUserLeaveHint} are intended to help
     * activities manage status bar notifications intelligently; specifically,
     * for helping activities determine the proper time to cancel a notfication.
     *
     * <p>All calls to your activity's {@link #onUserLeaveHint} callback will
     * be accompanied by calls to {@link #onUserInteraction}.  This
     * ensures that your activity will be told of relevant user activity such
     * as pulling down the notification pane and touching an item there.
     *
     * <p>Note that this callback will be invoked for the touch down action
     * that begins a touch gesture, but may not be invoked for the touch-moved
     * and touch-up actions that follow.
     *
     * @see #onUserLeaveHint()
     */
    public void onUserInteraction() {
    }

這裡貼上google翻譯的結果:
每當將關鍵,觸控或軌跡球事件傳送到活動時,都會呼叫該物件。 如果您希望知道使用者在您的活動正在執行時以某種方式與裝置進行了互動,則可以實現此方法。 此回撥和{@link #onUserLeaveHint}旨在幫助智慧地管理狀態列通知的活動; 具體來說,幫助活動確定正確的時間取消通知。所有呼叫活動的{@link #onUserLeaveHint}回撥將伴隨著對{@link #onUserInteraction}的呼叫。 這將確保您的活動將被告知相關的使用者活動,例如拉下通知窗格並在其中觸控一個專案。請注意,這個回撥將被呼叫,以觸發動作開始觸控手勢,但可能不會被呼叫 觸控移動和接下來的動作。

我覺得大概意思就是這個方法在我們有觸控事件到達我們的應用時都會呼叫,這個方法可以配合onUserLeaveHint()方法管理狀態列通知的取消。以前我都沒有注意到管理狀態列通知這方面知識,找個時間可以看看,這裡先不深入。
再下來是一個判斷。點開判斷條件的原始碼可以看到如下程式碼:

 /**
     * Used by custom windows, such as Dialog, to pass the touch screen event
     * further down the view hierarchy. Application developers should
     * not need to implement or call this.
     *
     */
    public abstract boolean superDispatchTouchEvent(MotionEvent event);

谷歌翻譯如下:
由自定義視窗(如Dialog)使用,可以在檢視層次結構下進一步傳遞觸控式螢幕事件。 應用程式開發人員不需要實現或呼叫這個。
我的理解是當有dailog之類的置於Activity之上時,此時dialog會消費掉觸控事件,正如我們平常看到的一樣,觸控dialog不會觸發Activity、View、ViewGroup的觸控事件,因此這裡直接return true,不在Activity中對觸控事件進行處理。
最後一句則是預設Activity是向下分發觸控事件。
Activity中沒有攔截事件,我們來看看消費事件。消費事件對應的是onTouchEvent方法。

    /**
     * Called when a touch screen event was not handled by any of the views
     * under it.  This is most useful to process touch events that happen
     * outside of your window bounds, where there is no view to receive it.
     *
     * @param event The touch screen event being processed.
     *
     * @return Return true if you have consumed the event, false if you haven't.
     * The default implementation always returns false.
     */
    public boolean onTouchEvent(MotionEvent event) {
        if (mWindow.shouldCloseOnTouch(this, event)) {
            finish();
            return true;
        }

        return false;
    }

註釋的意思大概是一些觸控事件當你的Activity中沒有View消耗掉時,該方法用來接受並處理掉這些觸控事件。
接著我們看程式碼。如果Activity消費掉觸控事件返回true,如果沒有則返回false。
到Window類中看判斷語句中的方法的原始碼。

    /** @hide */
    public boolean shouldCloseOnTouch(Context context, MotionEvent event) {
        if (mCloseOnTouchOutside && event.getAction() == MotionEvent.ACTION_DOWN
                && isOutOfBounds(context, event) && peekDecorView() != null) {
            return true;
        }
        return false;
    }

註釋中的@hide的意思可以看我另外一篇部落格
http://blog.csdn.net/flyyyyyyyy_/article/details/78340949
第一個判斷條件沒看出來是什麼意思,第二個意思是觸控事件為DOWN時,即觸控事件剛開始的時候就要判斷然後進行處理,第三個和第四個都與Android中的DecorView有關係,這裡來說說DecorView的概念。

private boolean isOutOfBounds(Context context, MotionEvent event) {
        final int x = (int) event.getX();
        final int y = (int) event.getY();
        final int slop = ViewConfiguration.get(context).getScaledWindowTouchSlop();
        final View decorView = getDecorView();
        return (x < -slop) || (y < -slop)
                || (x > (decorView.getWidth()+slop))
                || (y > (decorView.getHeight()+slop));
}
/**
     * Retrieve the current decor view, but only if it has already been created;
     * otherwise returns null.
     *
     * @return Returns the top-level window decor or null.
     * @see #getDecorView
     */
    public abstract View peekDecorView();

/**
     * Retrieve the top-level window decor view (containing the standard
     * window frame/decorations and the client's content inside of that), which
     * can be added as a window to the window manager.
     *
     * <p><em>Note that calling this function for the first time "locks in"
     * various window characteristics as described in
     * {@link #setContentView(View, android.view.ViewGroup.LayoutParams)}.</em></p>
     *
     * @return Returns the top-level window decor view.
     */
    public abstract View getDecorView();

這裡有關於DecorView的英文介紹,
google翻譯是:檢索頂級視窗裝飾檢視(包含標準視窗框架/裝飾和客戶端的內容),可以作為視窗新增到視窗管理器。
我的理解是最頂級的Window中的View,也就是說觸控事件先從DecorView開始傳遞,一層一層往下傳。
第三個判斷條件就是是否超出應用顯示的最頂層,第四個就是判斷最頂層檢視是否被建立。這裡判斷的意思是如果觸控超出Activity並且頂層檢視存在則關閉Activity。(還是不太懂這裡的意思。)

總結:觸控事件在Activity中的傳播是這樣的,首先dispatchTouchEvent分發事件判斷是否有如Dialog的Window覆蓋在上面並且判斷是否消耗掉觸控事件了,如果消耗掉則返回true事件不分發,如果沒有則交由消費者onTouchEvent處理。消費者onTouchEvent如果根據相關規則處理了觸控事件則返回true,觸控事件不分發,返回false則向下分發。

相關推薦

AndroidActivity觸控事件傳遞原始碼學習

Activity中的觸控事件傳遞對應兩個方法:dispatchTouchEvent和onTouchEvent。分別是分發和消費。 先來看分發。 /** * Called to process touch screen events. You

Android觸控事件傳遞機制學習筆記

1、Android 觸控事件傳遞機制 http://blog.csdn.net/awangyunke/article/details/22047987 2、Android-onInterceptTouchEvent()和onTouchEvent()總結 h

AndroidActivity之間引數傳遞

Intent:一直穿梭在Activity之間,它不光只是為了使Activity之間進行跳轉。在跳轉的時候,還可以進行Acivity之間的引數傳遞。 下面舉幾個列子。以MianActivity,TheActivity為例子。     MianActivity類     In

AndroidTouchEvent觸控事件機制

當我們的手指在Android螢幕上點選或滑動時,就會觸發觸控事件TouchEvent。在App中ViewGroup和View存在多級巢狀,在最外層的是Activity,最內層的View,介於Activity與View之間的是一些ViewGroup。本文為了簡化討

淺談AndroidActivity觸控事件傳輸機制介紹

8 Activity觸控事件傳輸機制介紹 當我們觸控式螢幕幕的時候,程式會收到對應的觸控事件,這個事件是在app端去讀取的嗎?肯定不是,如果app能讀取,那會亂套的,所以app不會有這個許可權,系統按鍵的讀取以及分發都是通過WindowManagerService來完成

Androidactivity之間如何傳遞Hashmap資料

我的使用場景是當一個頁面需頁面中的listview中的hashmap的資料時要另一個,就要用到了傳遞hashmap資料。 在傳送方,我的程式碼是這樣的: package cn.oddcloud.ww

Android O: 觸控事件傳遞流程原始碼分析(上)

前面的部落格中,我們通過例子分析了一下Android中事件傳遞的流程, 詳細內容可以參考:Android觸控事件傳遞機制簡要分析 貫穿整個Android的觸控事件分發的流程,基本可以抽象成以下的虛擬碼: public boolean dispatchT

android 觸控事件傳遞(一)

android 觸控事件傳遞 1、主要相關程式碼路徑 基於展訊7.0原始碼 native frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp frameworks

Android 觸控事件傳遞機制

android系統中的每個View的子類都具有下面三個和TouchEvent處理密切相關的方法:1)public boolean dispatchTouchEvent(MotionEvent ev)  這個方法用來分發TouchEvent2)public boolean onInterceptTouchEve

android觸控事件傳遞機制

看到一篇文章,將事件傳遞機制講得很透徹 【場景】 在cy的Home頁,每個點選塊都是自定義view來做的,組要用自定義自合view,如果需要將其中點選image和text分別有不同的反應,則應該去設定處理事件? 【詳情】 Android系統中的每個View的子類都具有下面三

初識Android觸控事件傳遞機制

前言 今天總結的一個知識點是Andorid中View事件傳遞機制,也是核心知識點,相信很多開發者在面對這個問題時候會覺得困惑,另外,View的另外一個難題滑動衝突,比如在ScrollView中巢狀ListView,都是上下滑動,這該如何解決呢,它解決的依據就是View事件的傳遞機制,所以開發者需要對View的

Android ViewGroup 觸控事件傳遞機制

引言 上一篇部落格我們學習了Android View 觸控事件傳遞機制,不瞭解的同學可以檢視Android View 觸控事件傳遞機制。今天繼續學習Android觸控事件傳遞機制,這篇部落格將和大家一起探討ViewGroup的觸控事件傳遞機制。 示例

Android觸控事件傳遞機制簡要分析

Android開發中經常會遇到多個View、ViewGroup巢狀的情況, 此時就可能遇到滑動衝突的問題。 為了這種問題,就必須對View的事件傳遞機制有一定的瞭解。 本篇部落格就以一些簡單的例子, 來看看Activity、View、ViewGroup三

Android 觸控事件傳遞流程解析

android中的Touch事件都是從ACTION_DOWN開始的: 單手指操作:ACTION_DOWN---ACTION_MOVE----ACTION_UP 多手指操作:ACTION_DOWN---ACTION_POINTER_DOWN---ACTION_MOV

android view觸控事件傳遞機制測試

沒有其它人為干預時: 詳細測試可以參考Github中的程式,地址: https://github.com/yifan42421/PhoneToPhoneScreen/tree/master/testmotionevent

android 觸控事件傳遞機制與筆記

一、筆記連結1. android 觸控事件傳遞機制2. android OnTouchListener,onTouchEvent,onClickListener執行順序 二、簡記1. android 觸控事件傳遞機制1.1Touch事件分發中只有兩個主角:ViewGroup和

Android觸控事件傳遞機制實踐——可拖動、大小切換的SizeSwitchView

前言   對於Android的觸控事件傳遞機制,網上有很多講解,有結合原始碼的,有圖文結合的,其中不乏一些講解清晰明瞭的文章,看完之後都能有所收穫。然而,理論終究是要應用在實踐上的,最近工作的時候,做出了一個可拖動,可以大小切換,大形態巢狀著ViewG

AndroidActivity與Fragment之間資料相互傳遞

一、Activity啟動Activity Intent intent = new Intent(this,MainListActivity.class); startActivity(intent); Activity與Activity傳遞資料 I

Android觸控事件傳遞機制,這一篇就夠了

整個觸控事件牽涉到的是,Activity,View,ViewGroup三者的傳遞機制。 這個觸控事件就是從外層往內層一層層的傳遞。 整個傳遞機制,分為3個步驟:分發,攔截,和消費。 1. 觸控事件的型別 事件型別是MotionEvent類:看下最新的sdk29的原始碼,一堆的Action,我們常用的其實就3個

AndroidActivity被系統會收前頁面信息保存

prot 判斷 edi 1.5 protected 是否為空 信息保存 android and 1、重寫onSaveInstanceState方法 protected void onSaveInstanceState(Bundle outState) { super