溫故而知新,系統(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ī)制完全解析,帶你從源碼的角度徹底理解(下)