事件分發(fā)

知識要點:

1.dispatchTouchEvent(MotionEvent ev)

2.onInterceptTouchEvent(MotionEvent ev)

3.onTouchEvent(MotionEvent ev)

目標要求:

掌握事件分發(fā)機制

一. 基礎認知

  1. 事件分發(fā)的對象是誰着撩?點擊事件(Touch事件)
  • 定義:當用戶觸摸屏幕時(View 或 ViewGroup派生的控件)审胸,將產生點擊事件(Touch事件)
    Touch事件的相關細節(jié)(發(fā)生觸摸的位置、時間等)被封裝成MotionEvent對象

  • 事件類型(4種)

事件類型 具體動作
MotionEvent.ACTION_DOWN 按下View(所有事件的開始)
MotionEvent.ACTION_UP 抬起View(與DOWN對應)
MotionEvent.ACTION_MOVE 滑動View
MotionEvent.ACTION_CANCEL 結束事件(非人為原因)

特別說明:從手指接觸屏幕 至 手指離開屏幕围肥,這個過程產生的一系列事件

注:一般情況下峭咒,事件列都是以DOWN事件開始鳍咱、UP事件結束荣刑,中間有無數(shù)的MOVE事件绒极,如下圖:

image
  1. 事件分發(fā)的本質
    將點擊事件(MotionEvent)傳遞到某個具體的View & 處理的整個過程
    即 事件傳遞的過程 = 分發(fā)過程骏令。

  2. 事件在哪些對象之間進行傳遞?
    Activity集峦、ViewGroup伏社、View
    Android的UI界面由Activity、ViewGroup塔淤、View 及其派生類組成

    image
  3. 事件分發(fā)的順序
    即 事件傳遞的順序:Activity -> ViewGroup -> View

  4. 事件分發(fā)過程由哪些方法協(xié)作完成?

    image

二.分發(fā)流程

image
Touch事件相關方法 Activity ViewGroup View
dispatchTouchEvent(MotionEvent ev)
onInterceptTouchEvent(MotionEvent ev) 沒有 沒有
onTouchEvent(MotionEvent event)
  1. Activity
  • dispatchTouchEvent(MotionEvent ev) -- 事件分發(fā)

    1.返回true 直接消費掉 ,沒有分發(fā);

    2.返回false,不消費,但是觸摸事件不做處理;

    3.只有返回super.dispatchTouchEvent(ev)事件才會向子view分發(fā),其實是調用了PhoneWindow的superDispatchTouchEvent(),進而調用了DecorView的superDispatchTouchEvent,里面又調用了super.dispatchTouchEvent(),而DecorView是一個FrameLayout

  • onTouchEvent(MotionEvent event) --事件處理
    1.返回false和默認(super.onTouchEvent(event)),不做處理;
    2.返回true,消費事件

  1. ViewGroup
  • dispatchTouchEvent(MotionEvent ev) -- 事件分發(fā)

    1.返回true 事件被消費了, 事件未分發(fā)

    2.返回false 事件未分發(fā),事件傳遞到父容器的onTouchEvent()

    3.只有返回super.dispatchTouchEvent(ev),事件才會向下走,里面會調用onInterceptTouchEvent()

  • onInterceptTouchEvent(MotionEvent ev) -- 事件攔截

    1.返回true,事件攔截,調用自己的onTouchEvent()

    2.返回false,事件未攔截,分發(fā)給了子view

    3.super.onInterceptTouchEvent(ev)與返回false效果一樣

  • onTouchEvent(MotionEvent event)

    1.返回false和super.onTouchEvent(event)事件不消費,事件傳遞給父容器
    2.返回true,事件會被消費

  1. View
  • dispatchTouchEvent(MotionEvent event)

    因為它最小,沒有子view,所以這個方法其實沒有進行分發(fā)的能力

    1.返回true,事件被消費,

    2.返回false ,事件傳遞到父容器的onTouchEvent()

    3.只有返回super.dispatchTouchEvent(ev),事件才會向下走,里面會調用自己 onTouchEvent()

  • onTouchEvent(MotionEvent event)

    1.返回false和super.onTouchEvent(event)事件不消費,事件傳遞給父容器
    2.返回true,事件會被消費

三.點擊事件觸發(fā)的位置及攔截
在onTouchEvent() 方法中MotionEvent.ACTION_UP中會調用performClick(),performClick()中會調用onClick()
攔截點擊事件: 在父容器中重寫 onInterceptTouchEvent(MotionEvent ev) ,返回true,會走父容器的onTouchEvent()方法

四.setOnTouchListener()和onTouchEvent()關系
源碼如下:

public boolean dispatchTouchEvent(MotionEvent event) {
      ...
        if (onFilterTouchEventForSecurity(event)) {

            if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;
            }

            if (!result && onTouchEvent(event)) {
                result = true;
            }
        }
        ...
        return result;
    }

第7行會調用OnTouchListener.onTouch(this, event),在第11行,才會去調用onTouchEvent(event),所以setOnTouchListener的onTouch()方法先被調用,如果onTouch()方法返回true,事件被消費了,則onTouchEvent()方法不會調用.

五.滑動事件沖突

父容器想獲取左右滑動事件,子view想獲取垂直滑動事件(如Viewpager中有ListView),都想獲取事件,怎么辦?

思路:可以進行選擇性的攔截事件,當水平滑動的距離大于垂直滑動的距離時,攔截事件

  @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        //選擇性的進行攔截,當水平滑動距離大于垂直滑動距離時 ,攔截
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mDownX = ev.getX();
                mDownY = ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                float moveX = ev.getX();
                float moveY = ev.getY();
                //水平和垂直的滑動距離(絕對值)
                float dx = Math.abs(moveX - mDownX);
                float dy = Math.abs(moveY- mDownY);
                if (dx>dy){
                    return true;
                }
                break;
        }

        return false;//不攔截
    }

  • getX()和getY():由這兩個函數(shù)獲得的x,y值是相對的坐標值速妖,相對于父容器坐標高蜂。

  • getRawX()和getRawY():有這兩個函數(shù)獲得的x,y值是絕對坐標,是相對于屏幕的罕容。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末备恤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子锦秒,更是在濱河造成了極大的恐慌露泊,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件旅择,死亡現(xiàn)場離奇詭異惭笑,居然都是意外死亡,警方通過查閱死者的電腦和手機生真,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門沉噩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人柱蟀,你說我怎么就攤上這事川蒙。” “怎么了长已?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵畜眨,是天一觀的道長昼牛。 經常有香客問我,道長康聂,這世上最難降的妖魔是什么贰健? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮早抠,結果婚禮上霎烙,老公的妹妹穿的比我還像新娘。我一直安慰自己蕊连,他們只是感情好悬垃,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著甘苍,像睡著了一般尝蠕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上载庭,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天看彼,我揣著相機與錄音,去河邊找鬼囚聚。 笑死靖榕,一個胖子當著我的面吹牛,可吹牛的內容都是我干的顽铸。 我是一名探鬼主播茁计,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼谓松!你這毒婦竟也來了星压?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤鬼譬,失蹤者是張志新(化名)和其女友劉穎娜膘,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體优质,經...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡竣贪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了盆赤。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贾富。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖牺六,靈堂內的尸體忽然破棺而出颤枪,到底是詐尸還是另有隱情,我是刑警寧澤淑际,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布畏纲,位于F島的核電站扇住,受9級特大地震影響,放射性物質發(fā)生泄漏盗胀。R本人自食惡果不足惜艘蹋,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望票灰。 院中可真熱鬧女阀,春花似錦、人聲如沸屑迂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽惹盼。三九已至庸汗,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間手报,已是汗流浹背蚯舱。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留掩蛤,地道東北人枉昏。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像揍鸟,于是被迫代替她去往敵國和親凶掰。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內容