View的觸摸事件機(jī)制

溫故而知新,系統(tǒng)整理一下。

1. View是什么?

 1. 觸摸事件的基本類型
      1). down: 按下
      2). move: 移動(dòng)
      3). up: 離開

2. 事件對(duì)象產(chǎn)生的順序

      1). down-->move-->move-->....-->up
      2). 每個(gè)事件對(duì)象產(chǎn)生后, 都會(huì)找到一個(gè)消費(fèi)者來(lái)消費(fèi)處理此事件

3. 事件相關(guān)API

      1). MotionEvent: 代表對(duì)UI的操作單元的類, 它的對(duì)象在用戶觸摸UI時(shí)系統(tǒng)自動(dòng)創(chuàng)建基對(duì)象, 并將相關(guān)的數(shù)據(jù)保存在此對(duì)象中
 ACTION_DOWN=0 : down類型值A(chǔ)CTION_UP=1 : up類型值 ACTION_MOVE=2 : move類型值 int getAction() : 得到事件類型值
 float getX() : 得到事件的X軸坐標(biāo)(相對(duì)于當(dāng)前View的左頂點(diǎn))float getRawX() : 得到事件的X軸坐標(biāo)(相對(duì)于屏幕的左頂點(diǎn))float getY() : 得到事件的Y軸坐標(biāo)(相對(duì)于當(dāng)前View的左頂點(diǎn))
 float getRawY() : 得到事件的Y軸坐標(biāo)(相對(duì)于屏幕的左頂點(diǎn))
      2). Activity
                boolean dispatchTouchEvent(MotionEvent event) : 分發(fā)事件  
                boolean onTouchEvent(MotionEvent event) : 處理事件的回調(diào)
      3). View
                boolean dispatchTouchEvent(MotionEvent event): 分發(fā)事件
             
                setOnClickListener(OnClickListener l) : 設(shè)置觸摸事件監(jiān)聽器對(duì)象
                private OnTouchListener mOnTouchListener; //觸摸事件監(jiān)聽器對(duì)象變量
                public interface OnTouchListener {  //事件監(jiān)聽器接口
                   boolean onTouch(View v, MotionEvent event);  // 監(jiān)聽器對(duì)象的回調(diào)方法
                }
 
                boolean onTouchEvent(MotionEvent event)  : 事件監(jiān)聽回調(diào)方法
 
                setOnclickListener(OnclickListener listener) : 設(shè)置點(diǎn)擊監(jiān)聽器
                setOnLongClickListener(OnLongClickListener listener) : 設(shè)置長(zhǎng)按事件監(jiān)聽器
      4). ViewGroup
                boolean dispatchTouchEvent(MotionEvent ev) : 重寫View的此方法, 如果當(dāng)前ViewGroup不攔截, 會(huì)分發(fā)給對(duì)應(yīng)的子View處理事件
                boolean onInterceptTouchEvent(MotionEvent ev) : 攔截觸摸事件, 返回值如果為true表示攔截,后面的事件就會(huì)交給當(dāng)前View來(lái)處理, 默認(rèn)為false
                requestDisallowInterceptTouchEvent(boolean disallowIntercept) : 如果參數(shù)為true, 使當(dāng)前View及其外層的所有父View不能攔截后面的事件

4. View的事件處理

      1). Touch事件的方法執(zhí)行順序: 
           ①. dispatchTouchEvent()
           ②. setOnTouchListener的onTouch()
           ③. onTouchEvent()
      2). 執(zhí)行的詳細(xì)過(guò)程
           ①. 在dispatchTouchEvent()會(huì)判斷是否設(shè)置了Touch監(jiān)聽器?
                如果沒(méi)有直接進(jìn)入②
                如果有, 調(diào)用監(jiān)聽器的onTouch()方法, 如果onTouch方法返回true到此結(jié)束, 如果返回false進(jìn)入②
           ②. 調(diào)用onTouchEvent()
                在down時(shí), send一個(gè)延時(shí)500ms的消息準(zhǔn)備觸發(fā)長(zhǎng)按事件監(jiān)聽回調(diào))
                如果0.5s內(nèi)在產(chǎn)生了up事件, 此時(shí)就會(huì)移除長(zhǎng)按的延時(shí)消息, 就會(huì)去執(zhí)行點(diǎn)擊事件監(jiān)聽回調(diào)
                如果0.5內(nèi)沒(méi)有產(chǎn)生up事件, 也沒(méi)有離開, 就會(huì)調(diào)用長(zhǎng)按事件監(jiān)聽回調(diào)方法, 如果返回的值是true就不可能再觸發(fā)點(diǎn)擊監(jiān)聽回調(diào)了, 否則還會(huì)觸發(fā).
      3). 說(shuō)明:
           ①. 如果view的onTouch()(監(jiān)聽器回調(diào))或onTouchEvent(監(jiān)聽回調(diào))在down時(shí)返回true, 那第一個(gè)move事件就會(huì)交給當(dāng)前View處理, 
                否則后面的所有事件都不會(huì)到達(dá)此View了
           ②. 如是move事件處理返回true, 下一個(gè)move/up事件就會(huì)交給當(dāng)前View處理,否則就會(huì)找父View或Activity處理
           ③. 整體原則: 每個(gè)Event對(duì)象創(chuàng)建后, 最終肯定會(huì)有一個(gè)消費(fèi)者: 可能是View, 也可能是ViewGroup, 實(shí)在不行就交給Activty消費(fèi)處理

5. ViewGroup的事件處理

      1). 相關(guān)方法執(zhí)行順序:
           ①. dispatchTouchEvent()
           ②.onInterceptTouchEvent()
           ③. 對(duì)應(yīng)子View的dispatchTouchEvent()
      2). 執(zhí)行的詳細(xì)過(guò)程:
           ①. 在dispatchTouchEvent()中, ACTION_DOWN時(shí), 判斷是否攔截,如果沒(méi)有攔截,則找到包含當(dāng)前x,y坐標(biāo)的子View,賦值給mMotionTarget,
                然后調(diào)用mMotionTarget.dispatchTouchEvent()處理down事件
           ②. 在dispatchTouchEvent()中, ACTION_MOVE時(shí), 判斷是否攔截,如果沒(méi)有攔截,則直接調(diào)用mMotionTarget.dispatchTouchEvent(ev)
           ③. 在dispatchTouchEvent()中, ACTION_UP時(shí), 判斷是否攔截,如果沒(méi)有攔截,則直接調(diào)用mMotionTarget.dispatchTouchEvent(ev)
           ④. 如果沒(méi)有找到合適的子View來(lái)消費(fèi)當(dāng)前event, 則將自己當(dāng)成View來(lái)處理event
      3). 關(guān)于攔截:
           ①. 如何攔截?: ViewGroup中onInterceptTouchEvent()默認(rèn)返回false, 也就是不攔截, 如果想攔截就重寫此方法, 并返回true, 這樣事件就不會(huì)分發(fā)給子View處理
           ②. 如何不被攔截?: 如果子View不希望父View(也就是當(dāng)前ViewGroup)攔截event, 子View可以執(zhí)行: getParent().requestDisallowInterceptTouchEvent(true)

------相關(guān)資料推薦
Android View 事件分發(fā)機(jī)制 源碼解析
Android ViewGroup事件分發(fā)機(jī)制
Android事件分發(fā)機(jī)制完全解析,帶你從源碼的角度徹底理解(上)
Android事件分發(fā)機(jī)制完全解析,帶你從源碼的角度徹底理解(下)

android觸摸事件處理流程
Android應(yīng)用層View繪制流程與源碼分析

Android View刷新機(jī)制

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,001評(píng)論 25 709
  • 介紹自己負(fù)責(zé)的部分,如何實(shí)現(xiàn)的。 框架的搭建排查問(wèn)題以及結(jié)解決方式兼容性保證性能優(yōu)化上線之后模塊導(dǎo)致crash的比...
    黃海佳閱讀 13,392評(píng)論 6 350
  • 這是android伸手黨知識(shí)收集系列的第六篇,來(lái)整理android開發(fā)進(jìn)階相關(guān)知識(shí):Window,View,事件分...
    passiontim閱讀 15,757評(píng)論 10 150
  • 威虎閱讀 448評(píng)論 0 0
  • 一,背景介紹 鈴木敏文,日本7-Eleven的創(chuàng)始人,一個(gè)從出版屆跨界進(jìn)入零售屆的經(jīng)營(yíng)奇才。在20世紀(jì)70年代大型...
    不知所然并卵閱讀 1,841評(píng)論 0 1

友情鏈接更多精彩內(nèi)容