Android 事件分發(fā)機制

Android 事件分發(fā)一直都是一個難點刻坊,讓人很模糊好爬,感覺自己知道點,但又不是很清楚奶卓。最重要的是我知道了理論一疯,怎么沒感覺在實際開發(fā)中用到呢撼玄?今天決定來好好研究一下這個事件分發(fā)機制夺姑,如有不正確的地方,請多多指教掌猛。


假設(shè)這是手機界面圖.png

首先看上圖盏浙,我們要知道這個層次關(guān)系,你可以把每一層理解為一張紙放在桌子上荔茬,那就是Activity這張紙在最下面废膘,ViewGroup在Activity的上面,View在ViewGroup的上面慕蔚。

好了丐黄,理解完層次關(guān)系,我們可以點一下View內(nèi)任意一點孔飒。這時View是接受了一個事件(先不用管是什么事件灌闺,隨便你就理解為一個ACTION_DOWN事件)。到這里我要說下我原來的錯誤認(rèn)識坏瞄,做個反面教程桂对,讓大家更好的理解。我原來認(rèn)為鸠匀,View最先接收到到事件蕉斜,所以事件的傳遞肯定是View---ViewGroup---Activity這樣由外往里傳遞的。

其實不然缀棍,你可以這樣理解宅此。Activity、ViewGroup爬范、View是一個部門的三個同事诽凌,只不過Activity是部門主任,ViewGroup是主管坦敌,View是一個職員侣诵。

突然有一天View接受到一個任務(wù)(觸摸事件)痢法,那我們要想一下這個任務(wù)是怎么來的呢,無論這個任務(wù)是你自己部門內(nèi)部的杜顺,還是兄弟部門的協(xié)作任務(wù)财搁。只要給你分配任務(wù),那都要必須經(jīng)過你的主任和主管的同意躬络,因為他們是你的頂頭上司尖奔,而你是他們的干將。所以說這個任務(wù)也就是這個事件穷当,在傳到View之前提茁,早已經(jīng)經(jīng)過了你的領(lǐng)導(dǎo)的同意,也就是早就經(jīng)過了Activity和ViewGroup馁菜。如果領(lǐng)導(dǎo)不同意茴扁,或是半路領(lǐng)導(dǎo)就一句話的事幫你把事給解決了。那這個任務(wù)也就不會傳遞到View這來了汪疮。

總結(jié):雖然我們是對View發(fā)起了觸摸事件峭火,但是事件的傳遞開始于Activity。由Activiy----ViewGroup---View智嚷。

好了卖丸,到這里大體知道了事件傳遞流程了。但是我們還要知道幾個重要的方法盏道。如下圖所示稍浆,除了ViewGroup多了一個onInterceptTouchEvent方法外,他們都有dispatchTouchEventonTouchEvent猜嘱。

方法.png

接下來我們看看這幾個方法都是什么意思衅枫,還是說下我原來的認(rèn)識誤區(qū)。我原來認(rèn)為dispatchTouchEvent是事件分發(fā)的方法泉坐,所以它返回true代表向下分發(fā)事件为鳄,false代表不向下分發(fā),如果return super. dispatchTouchEvent()腕让,我就認(rèn)為交給父類處理孤钦。

我當(dāng)時的認(rèn)知是不完全正確的,那說下這幾個方法分別返回 true或false或是return super.xxx到底是什么意思纯丸。
  • dispatchTouchEvent
    true:代表消費掉事件偏形,不再向下傳遞
    false:代表不向下分發(fā)事件,不處理觉鼻,再把事件返還到上一層
    super:表示繼續(xù)向下傳遞
  • onInterceptTouchEvent
    true: 代表攔截事件俊扭,不向下傳遞,交給自己的onTouchEvent處理
    false和super:都表示不攔截坠陈,繼續(xù)向下傳遞事件
  • onTouchEvent:
    true:表示消費掉事件
    false:Activity中表示丟棄事件不處理萨惑,而如果是在ViewGroup和View中表示自己不處理捐康,交給上級
    super:交給上級處理

這里還要區(qū)分是誰的dispatchTouchEvent方法,Activity和View的這個方法同樣的返回值庸蔼,所做的操作是有區(qū)別的解总。詳細(xì)可以看下面的流程圖

是時候展示真正的技術(shù)了:我看了好多類似的事件分發(fā)流程圖,乍眼一看都有點蒙圈姐仅,覺得好凌亂復(fù)雜花枫。所以我也畫了一個圖,個人認(rèn)為還算清晰簡潔掏膏。

Android事件分發(fā)機制流程圖.png

你不需要太仔細(xì)看這個圖劳翰,先簡單的看下。然后就是需要自己擼代碼驗證的時刻了馒疹,這時會加深你的理解佳簸。擼代碼回來再仔細(xì)看,你就會恍然大明白了行冰。

那怎樣寫代碼溺蕉,很簡單:

  1. 先自定義一個ViewGroup繼承LinearLayout伶丐,重寫需要的幾個方法
  2. 自定義View繼承TextView悼做,重寫需要的方法
  3. 在Activity的布局代碼中加入你自定義的ViewGroup,ViewGroup里面是的自定義的TextView哗魂。Activity中重寫需要的方法肛走。
//自定義ViewGroup
public class MyViewGroup extends LinearLayout {

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

    public MyViewGroup(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public MyViewGroup(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

   /*************下面是我們需要的方法*************/

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e("ViewGroup", "dispatchTouchEvent");
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.e("ViewGroup", "onInterceptTouchEvent");
        return super.onInterceptTouchEvent(ev);
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("ViewGroup", "onTouchEvent");
        return super.onTouchEvent(event);
    }
}
//自定義TextView
public class MyTextView extends android.support.v7.widget.AppCompatTextView {

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

    public MyTextView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public MyTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

  /*************下面是我們需要的方法*************/
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.e("View", "dispatchTouchEvent");
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("View", "onTouchEvent");
        return super.onTouchEvent(event);
    }
}
//Activity中的代碼
public class Main6Activity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main6);
    }

  // 這里只打印ACTION_DOWN的傳遞,不然會有移動和抬起的事件录别,在一起比較亂
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction()==MotionEvent.ACTION_DOWN){
            Log.e("Activity", "dispatchTouchEvent");
            return super.dispatchTouchEvent(ev);
        }
        return false;
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("Activity", "onTouchEvent");
        return super.onTouchEvent(event);
    }
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.zsl.aa.Main6Activity">

    <com.zsl.aa.MyViewGroup
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <com.zsl.aa.MyTextView
            android:id="@+id/tv_view"
            android:layout_width="120dp"
            android:layout_height="130dp"
            android:background="#ff00ff" />
    </com.zsl.aa.MyViewGroup>

</LinearLayout>

ok朽色,到這里準(zhǔn)備工作就完事了,非常簡單的代碼组题。運行程序后葫男,點下View看看打印結(jié)果。然后再分不同的情況崔列,分別更改返回的值為true或false或是super.xxx梢褐。分別看看打印情況,你就會知道了傳遞流程了赵讯。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末盈咳,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子边翼,更是在濱河造成了極大的恐慌鱼响,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,865評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件组底,死亡現(xiàn)場離奇詭異丈积,居然都是意外死亡筐骇,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,296評論 3 399
  • 文/潘曉璐 我一進店門江滨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拥褂,“玉大人,你說我怎么就攤上這事牙寞〗染椋” “怎么了?”我有些...
    開封第一講書人閱讀 169,631評論 0 364
  • 文/不壞的土叔 我叫張陵间雀,是天一觀的道長悔详。 經(jīng)常有香客問我,道長惹挟,這世上最難降的妖魔是什么茄螃? 我笑而不...
    開封第一講書人閱讀 60,199評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮连锯,結(jié)果婚禮上归苍,老公的妹妹穿的比我還像新娘。我一直安慰自己运怖,他們只是感情好拼弃,可當(dāng)我...
    茶點故事閱讀 69,196評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著摇展,像睡著了一般吻氧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上咏连,一...
    開封第一講書人閱讀 52,793評論 1 314
  • 那天盯孙,我揣著相機與錄音,去河邊找鬼祟滴。 笑死振惰,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的垄懂。 我是一名探鬼主播骑晶,決...
    沈念sama閱讀 41,221評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼埠偿!你這毒婦竟也來了透罢?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,174評論 0 277
  • 序言:老撾萬榮一對情侶失蹤冠蒋,失蹤者是張志新(化名)和其女友劉穎羽圃,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,699評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡朽寞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,770評論 3 343
  • 正文 我和宋清朗相戀三年识窿,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片脑融。...
    茶點故事閱讀 40,918評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡喻频,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出肘迎,到底是詐尸還是另有隱情甥温,我是刑警寧澤,帶...
    沈念sama閱讀 36,573評論 5 351
  • 正文 年R本政府宣布妓布,位于F島的核電站姻蚓,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏匣沼。R本人自食惡果不足惜狰挡,卻給世界環(huán)境...
    茶點故事閱讀 42,255評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望释涛。 院中可真熱鬧加叁,春花似錦、人聲如沸唇撬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,749評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽局荚。三九已至超凳,卻和暖如春愈污,著一層夾襖步出監(jiān)牢的瞬間耀态,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,862評論 1 274
  • 我被黑心中介騙來泰國打工暂雹, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留首装,地道東北人。 一個月前我還...
    沈念sama閱讀 49,364評論 3 379
  • 正文 我出身青樓杭跪,卻偏偏與公主長得像仙逻,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子涧尿,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,926評論 2 361

推薦閱讀更多精彩內(nèi)容