您好,登錄后才能下訂單哦!
Android事件流程詳解
網絡上有不少博客講述了android的事件分發機制和處理流程機制,但是看過千遍,總還是覺得有些迷迷糊糊,因此特地抽出一天事件來親測下,向像我一樣的廣大入門程序員詳細講述android事件背后的故事,話不多說,上干貨。
android整個事件流程主要牽扯到dispatchTouchEvent(),onInterceptTouchEvent(),
onTouchEvent()這三個方法,下表來說明這三個方法的功能和分布場景:
表1:
方法名稱 | 功解解說 | Activity | ViewGroup | View |
dispatchTouchEvent() | 事件分發 | YES | YES | YES |
onInterceptTouchEvent() | 事件攔截 | NO | YES | NO |
onTouchEvent() | 事件處理 | YES | YES | YES |
先來分析下Touch事件:所有Touch事件發生時會調用當前Activity的dispatchTouchEvent()方
法來分發事件,Activity的dispatchTouchEvent()方法最終會調用PhoneWindow類中的
superDispatchTouchEvent方法,最終邏輯就是該activity會調用ViewGroup類中的
dispatchTouchEvent()進行隧道式分發事件(按布局元素由外向內分發),如本案例中的分發流程
為TouchTraining -> TouchViewGroup -> TouchView,需要注意的是,當你在Activit中的
dispatchTouchEvent()中直接返回具體的布爾值(無論是true還是false),Touch事件直接會被
消費在該方法中,不會再進行下來的事件分發流程,因此必須在activity的dispatchTouchEvrent
返回super.dispatchTouchEvent()來進行事件分發流程。下面進行案例說明分析:
首先在定義自己的View和ViewGroup,重寫表1它們各自支持的事件流程方法,我這里自定ViewGroup
繼承的是LinearLayout(只要繼承的是ViewGroup都一樣),然后分別在Activity的布局文件中加入自定
義的控件,接著在Activity中也重寫它支持的事件流程方法。
activity_touchtrain.xml
TouchView(自定義View類)
@Override public boolean dispatchTouchEvent(MotionEvent event) { Log.e(TAG, "dispatchTouchEvent分發事件"+ TouchEventUtil.getTouchAction(event.getAction())); return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent ev) { Log.e(TAG, "onTouchEvent處理事件"+ TouchEventUtil.getTouchAction(ev.getAction())); return super.onTouchEvent(ev); }
TouchViewGroup(自定義ViewGroup類)
@Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.e(TAG, "dispatchTouchEvent分發事件" + TouchEventUtil.getTouchAction(ev.getAction())); return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { Log.e(TAG, "onInterceptTouchEvent攔截事件"+ TouchEventUtil.getTouchAction(ev.getAction())); return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent ev) { Log.e(TAG, "onTouchEvent處理事件"+ TouchEventUtil.getTouchAction(ev.getAction())); return super.onTouchEvent(ev); }
TouchTraining(Activity)
@Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.e(TAG, "dispatchTouchEvent分發事件"+ TouchEventUtil.getTouchAction(ev.getAction())); return super.dispatchTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent ev) { Log.e(TAG, "onTouchEvent處理事件"+ TouchEventUtil.getTouchAction(ev.getAction())); return super.onTouchEvent(ev); }
TouchEventUtils(工具類,獲取當前事件類型)
public static String getTouchAction(int actionId) { String actionName = "Unknow:id=" + actionId; switch (actionId) { case MotionEvent.ACTION_DOWN: actionName = "ACTION_DOWN"; break; case MotionEvent.ACTION_MOVE: actionName = "ACTION_MOVE"; break; case MotionEvent.ACTION_UP: actionName = "ACTION_UP"; break; case MotionEvent.ACTION_CANCEL: actionName = "ACTION_CANCEL"; break; case MotionEvent.ACTION_OUTSIDE: actionName = "ACTION_OUTSIDE"; break; } return actionName; }
案例分析
方案1
條件 | |||
控件名稱 | dispatchTouchEvent返回值 | onInterceptTouchEvent 返回值 | onTouchEvent 返回值 |
TouchTraining | super.dispatchTouchEvent(ev) | ---- | super.onTouchEvent(ev) |
TouchViewGroup | false | super.onInterceptTouchEvent(ev) | super.onTouchEvent(ev) |
TouchView | super.dispatchTouchEvent(ev) | ---- | super.onTouchEvent(ev) |
運行結果:
com.training.cj.mytraining E/TouchTraining: dispatchTouchEvent分發事件ACTION_DOWN
com.training.cj.mytraining E/TouchViewGroup: dispatchTouchEvent分發事件ACTION_DOWN
com.training.cj.mytraining E/TouchTraining: onTouchEvent處理事件ACTION_DOWN
com.training.cj.mytraining E/TouchTraining: dispatchTouchEvent分發事件ACTION_UP
com.training.cj.mytraining E/TouchTraining: onTouchEvent處理事件ACTION_UP
結果分析:Touch事件開始,調用TouchTraining的dispatchTouchEvent把事件分發TouchViewGroup
的dispatchTouchEvent,TouchViewGroup的dispatchTouchEvent返回false,事件停止向下傳遞,同
時事件并沒有消費,但由于該事件來自TouchTraining(Activity),所以最終返回給TouchTraining
的onTouchEvent進行消費。
方案2
條件 | |||
控件名稱 | dispatchTouchEvent返回值 | onInterceptTouchEvent 返回值 | onTouchEvent 返回值 |
TouchTraining | super.dispatchTouchEvent(ev) | ---- | super.onTouchEvent(ev) |
TouchViewGroup | true | super.onInterceptTouchEvent(ev) | super.onTouchEvent(ev) |
TouchView | super.dispatchTouchEvent(ev) | ---- | super.onTouchEvent(ev) |
運行結果:
com.training.cj.mytraining E/TouchTraining: dispatchTouchEvent分發事件ACTION_DOWN
com.training.cj.mytraining E/TouchViewGroup: dispatchTouchEvent分發事件ACTION_DOWN
com.training.cj.mytraining E/TouchTraining: dispatchTouchEvent分發事件ACTION_UP
com.training.cj.mytraining E/TouchViewGroup: dispatchTouchEvent分發事件ACTION_UP
結果分析:Touch事件由TouchTraining的dispatchTouchEvent不斷向TouchViewGroup分發,
TouchViewGroup的dispatchTouchEvent返回true,TouchViewGroup在dispatchTouchEvent中不斷消
費來自TouchTraining的dispatchTouchEvent分發的事件。
方案3
條件 | |||
控件名稱 | dispatchTouchEvent返回值 | onInterceptTouchEvent 返回值 | onTouchEvent 返回值 |
TouchTraining | super.dispatchTouchEvent(ev) | ---- | super.onTouchEvent(ev) |
TouchViewGroup | super.onInterceptTouchEvent(ev) | true | super.onTouchEvent(ev) |
TouchView | super.dispatchTouchEvent(ev) | ---- | super.onTouchEvent(ev) |
運行結果:
com.training.cj.mytraining E/TouchTraining: dispatchTouchEvent分發事件ACTION_DOWN
com.training.cj.mytraining E/TouchViewGroup: dispatchTouchEvent分發事件ACTION_DOWN
com.training.cj.mytraining E/TouchViewGroup: onInterceptTouchEvent攔截事件ACTION_DOWN
com.training.cj.mytraining E/TouchViewGroup: onTouchEvent處理事件ACTION_DOWN
com.training.cj.mytraining E/TouchTraining: onTouchEvent處理事件ACTION_DOWN
com.training.cj.mytraining E/TouchTraining: dispatchTouchEvent分發事件ACTION_UP
com.training.cj.mytraining E/TouchTraining: onTouchEvent處理事件ACTION_UP
結果分析:Touch事件發生,調用TouchTraining的dispatchTouchEvent分發事件到TouchViewGroup
的dispatchTouchEvent,TouchViewGroup的dispatchTouchEvent返回super.onInterceptTouchEvent(ev)進
行事件分發,事件向下傳遞給TouchViewGroup的onInterceptTouchEvent,TouchViewGroup的onInterceptTouchEvent返回true,事件被攔截并傳遞給TouchViewGroup的onTouchEvent進行消費,TouchViewGroup的onTouchEvent返回super.dispatchTouchEvent(ev),對Touch事件未消費并返回給上級控件的onTouchEvent進行消費,由于TouchViewGroup的Touch事件來自TouchTraining,所以最后 由TouchTraining的onTouchEvent進行消費。
方案4
條件 | |||
控件名稱 | dispatchTouchEvent返回值 | onInterceptTouchEvent 返回值 | onTouchEvent 返回值 |
TouchTraining | super.dispatchTouchEvent(ev) | ---- | super.onTouchEvent(ev) |
TouchViewGroup | super.onInterceptTouchEvent(ev) | false | super.onTouchEvent(ev) |
TouchView | super.dispatchTouchEvent(ev) | ---- | super.onTouchEvent(ev) |
運行結果:
com.training.cj.mytraining E/TouchTraining: dispatchTouchEvent分發事件ACTION_DOWN
com.training.cj.mytraining E/TouchViewGroup: dispatchTouchEvent分發事件ACTION_DOWN
com.training.cj.mytraining E/TouchViewGroup: onInterceptTouchEvent攔截事件ACTION_DOWN
com.training.cj.mytraining E/TouchView: dispatchTouchEvent分發事件ACTION_DOWN
com.training.cj.mytraining E/TouchView: onTouchEvent處理事件ACTION_DOWN
com.training.cj.mytraining E/TouchViewGroup: onTouchEvent處理事件ACTION_DOWN
com.training.cj.mytraining E/TouchTraining: onTouchEvent處理事件ACTION_DOWN
com.training.cj.mytraining E/TouchTraining: dispatchTouchEvent分發事件ACTION_UP
com.training.cj.mytraining E/TouchTraining: onTouchEvent處理事件ACTION_UP
結果分析:Touch事件發生,調用TouchTraining的dispatchTouchEvent分發事件到TouchViewGroup的dispatchTouchEvent,TouchViewGroup的dispatchTouchEvent返回super.onInterceptTouchEvent(ev),繼續分發向下傳遞事件到TouchViewGroup的onInterceptTouchEvent,TouchViewGroup的onInterceptTouchEvent返回false,繼續分發向下傳遞事件到TouchView的dispatchTouchEvent,TouchView的dispatchTouchEvent返回super.dispatchTouchEvent(ev),繼續分發向下傳遞事件到TouchView的onTouchEvent,TouchView的onTouchEvent返回super.onTouchEvent(ev),事件沒有消費,返回給上級TouchViewGroup的onTouchEvent進行消費,TouchViewGroup的
onTouchEvent返回super.onTouchEvent(ev),繼續返回給上級TouchTraining的onTouchEvent進行消費。
方案5:
條件 | |||
控件名稱 | dispatchTouchEvent返回值 | onInterceptTouchEvent 返回值 | onTouchEvent 返回值 |
TouchTraining | super.dispatchTouchEvent(ev) | ---- | super.onTouchEvent(ev) |
TouchViewGroup | super.onInterceptTouchEvent(ev) | false | super.onTouchEvent(ev) |
TouchView | true | ---- | super.onTouchEvent(ev) |
運行結果:
com.training.cj.mytraining E/TouchTraining: dispatchTouchEvent分發事件ACTION_DOWN
com.training.cj.mytraining E/TouchViewGroup: dispatchTouchEvent分發事件ACTION_DOWN
com.training.cj.mytraining E/TouchViewGroup: onInterceptTouchEvent攔截事件ACTION_DOWN
com.training.cj.mytraining E/TouchView: dispatchTouchEvent分發事件ACTION_DOWN
com.training.cj.mytraining E/TouchView: onTouchEvent處理事件ACTION_DOWN
com.training.cj.mytraining E/TouchTraining: dispatchTouchEvent分發事件ACTION_UP
com.training.cj.mytraining E/TouchViewGroup: dispatchTouchEvent分發事件ACTION_UP
com.training.cj.mytraining E/TouchViewGroup: onInterceptTouchEvent攔截事件ACTION_UP
com.training.cj.mytraining E/TouchView: dispatchTouchEvent分發事件ACTION_UP
com.training.cj.mytraining E/TouchView: onTouchEvent處理事件ACTION_UP
結果分析:Touch事件發生,調用TouchTraining的dispatchTouchEvent分發事件到TouchViewGroup的dispatchTouchEvent,該方法返回super.dispatchTouchEvent(ev),繼續分發事件到TouchViewGroup的onInterceptTouchEvent,該方法返回false,繼續分發事件到TouchView的dispatchTouchEvent,該方法返回super.dispatchTouchEvent(ev),繼續分發事件到onTouchEvent,由于onTouchEvent返回true,表示消費了事件,Touch事件終止。
好了,本期的Touch事件分析到這里就結束了,另外,還有一個小細節需要注意的是,在View和View Group中的onTouchEvent方法默認返回false,View Group中的onInterceptTouchEvent也默認返回false。所以上面5種方案描述出了所有的Touch事件傳遞可能。了解Touch事件的分發和消費機制,更有利于我們自定義控件,當然我們在自定義控件時,盡量不要重寫dispatchTouchEvent這個方法。
本貼參考博客:http://www.cnblogs.com/sunzn/archive/2013/05/10/3064129.html
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。