Android_事件紛發
關於事件你應該知道的是
當一個事件產生後,他的傳遞過程遵循如下順序Activity > Window > View
事件來源於activity,activity假如你沒有重寫任何關於事件紛發的方法的話,他會把事件傳遞給window,window將事件傳遞給decorView
現在我們來看下假如我們在activity中重寫了dispatchEvent的方法是什麼樣的一個情況.
我們把activity中的dispatchTouchEvent 返回true
事件被activity的dispatchTouchEvent消耗掉,所以activity的
onTouchEvent方法得不到響應,我們看下log輸出
很明顯的能看出來,log只列印了dispatchTouchEvent中的相關方法,整個事件被dispatchTouchEvent消耗掉,並沒有傳遞到我們的window > decorView 所有我介面的返回鍵接受不到事件,所以返回按鈕的點擊事件也沒生效,
我們在把activity中的dispatchTouchEvent返回false看看是什麼情況,,這也是我的一個疑問點,麻煩大神幫忙解答一下就是我activity中的dispatchTouchEvent返回了false,那麼事件標誌著事件沒人處理,此時事件的根源是從activity來的,如果他都不管的話,這個事件已經不能返回他的父view ,當前activity的onTouchEvent()也無log輸出,那麼事件哪裡去了????
然後我們看下返回false的log輸出如:
log輸出一隻執行了activity中的dispatchTouchEvent的相關方法,
TouchEvent並沒有任何輸出,表明activity的onTouchEvent也沒有接受到這個事件,此時我再點擊返回鍵,的onclick依然是失效的,
所以.麻煩大神幫忙解答下這一點,當activity中的dispatchtouchevent返回false,事件的流程是怎麼樣的,???
最後我們讓activity中的dispatchtouchevent 返回super看下
然後看下log日誌的輸出,以及log 的順序,
注意log的順序,dispatchTouchEvent down > onTouchEvent down
dispatchTouchEvent move > onTouchEvent move
dispatchTouchEvent up > onTouchEvent up
面試的時候注意面試官問的問題,和執行順序的問題
然後我們往activity中加入一個linearlayout,我們重寫一下linearlayout的有關事件的三個方法,並列印log看一下,暫時不往linearlayout中加入任何子view,單純的看一下事件從activity傳遞到viewgroup的效果.
首先我們在書寫一個TESTLinearlayout,如下
public class AAATestLinearlayout extends LinearLayout { private static final String TAG = "AAATestLinearlayout"; public AAATestLinearlayout(Context context) { super(context); } public AAATestLinearlayout(Context context, AttributeSet attrs) { super(context, attrs); } public AAATestLinearlayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: Logger.e(TAG, TAG + ">>>>dispatchTouchEvent.ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Logger.d(TAG, TAG + ">>>>dispatchTouchEvent.ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Logger.w(TAG, TAG + ">>>>dispatchTouchEvent.ACTION_UP"); break; }// return true; return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: Logger.e(TAG, TAG + ">>>>onInterceptTouchEvent.ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Logger.d(TAG, TAG + ">>>>onInterceptTouchEvent.ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Logger.w(TAG, TAG + ">>>>onInterceptTouchEvent.ACTION_UP"); break; }// return true; return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: Logger.e(TAG, TAG + ">>>>onTouchEvent.ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Logger.d(TAG, TAG + ">>>>onTouchEvent.ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Logger.w(TAG, TAG + ">>>>onTouchEvent.ACTION_UP"); break; } return super.onTouchEvent(event); }}
我們就先預設的讓測試的linearlayout全部返回super值.
看下事件傳遞的過程從activity > window > decorView > 我們自己的linearlayout;
並且我們在linearlayout中的構造中設定了額外的onTouchLinstener,
我們看下的結果;
這裡簡答描述一下,我們往activity中加入了一個linearlayout.並且在構造中給linearlayoutset了一個touchlistener.
我們從log可以看到,事件從activity中開始傳遞,然後我們在linearlayout中有關事件的方法全部返回super.
其中關於onInterceptTouchEvent
我想說兩句,這句話的傳回值影響的是viewgroup容器中子view的事件傳遞,並不會對當前的viewgroup的onTouchEvent或者set 的touchlistener有影響,我們從log可以看出來,linearlayout的 onTouchEvent.down 和 touchliste的down均執行了
假如onInterceptTouchEvent的值返回的是super的話,我們看viewgroup的源碼可以知道
預設是false,也就是不攔截…重要的是不攔截….
* appear here. * * * @param ev The motion event being dispatched down the hierarchy. * @return Return true to steal motion events from the children and have * them dispatched to this ViewGroup through onTouchEvent(). * The current target will receive an ACTION_CANCEL event, and no further * messages will be delivered here. */ public boolean onInterceptTouchEvent(MotionEvent ev) { return false; }
這是viewgroup的源碼,和Android藝術探索第143頁第六條說的完全吻合,
還有一篇部落格,應該是比較經典的,其中對onInterceptTouchEvent的解釋如下;
這裡部落格博主說是返回super的話預設被攔截,並把攔截的事件交給當前view,處理,
我們這裡的當前view就是我們的linearlayoutlayout 從log看確實執行了onTouchEvent.但是這個onTouchEvent並不是因為返回了super他沒有攔截而執行了.因為筆者試著返回true false,super,對我們設定的touchlistener和onTouchEvent的down事件沒有任何影響,
所以這塊我也迷茫了半天,看了書本和諮詢了群裡的nil大概猜測一下可能是博主理解有出入或者筆誤,再次留下部落格的地址:請大神批閱和校正一下原文連結如下Android編程下的事件紛發
接著說我們的情境,目前我們linearlayout中的事件處理方法均沒有對事件做處理,這樣我們linearlayout中的子view比如我們的返回按鈕確實能接收到事件,然後點擊返回箭頭,activity關閉,此事第一個情境走完.
第二個情境,我們把我們的liearlayout中的dispatchTouchEvent返回true,
我們猜想是這樣的,如果返回true,事件就在當前的方法中終止了也就是在liearlayout中終止,所以其他的方法根本不會接收到這個事件,所以看下我們執行的log輸出,
vcrCvP4s09rKx87Sw8e1xLe1u9iwtMWlvs3Kp9CnwcsuPC9wPg0KPHA+tdq2/rj2s6G+sCzO0sPHyMNsaW5lYXJsYXlvdXS1xGRpc3BhdGNob25Ub3VjaEV2ZW50t7W72GZhbHNlLMTHw7TV4rj2tKXD/srCvP69q8rH0ru49tT1w7TR+bXEuf2zzMTYPzwvcD4NCjxwPmRpc3BhdGNob25Ub3VjaEV2ZW50Lre1u9hmYWxzZSzKwrz+0qqxu8C019TExMDvLL7N0qqxu7e1u9jExMDvLLzZyOfO0sPHtcRsaW5lYXJsYXlvdXS7udPQuLh2aWV3ICzEx8O01eK49srCvP69q7e1u9i4+Li4dmlld7XEb25Ub3VjaEV2ZW50ysK8/rSmwO0syOe5+8C019RhY3Rpdml0eSzEx8O0vauxu2FjdGl2aXR5tcRvblRvdWNoRXZlbnS0psDtLL+0z8LO0sPHtcRsb2fK5LP2OzwvcD4NCjxwPjxpbWcgYWx0PQ=="這裡寫圖片描述" src="http://www.bkjia.com/uploads/allimg/160403/041R053C-12.png" title="\" />

當我們點擊我們的返回箭頭的時候,因為事件從liearlayout中返回給了activity消費,所以子控制項沒法接收到事件,所以點擊返回的箭頭也無法生效;
第三個情境,linearlayout中的onInterceptTouchEvent返回true,其他返回super,猜想,攔截事件返回true,那麼事件不會傳遞給子view,
返回按鈕不會生效.因為我們其他的方法都是返回到 super,所以事件在onTouchEvent中返回了給其父view 或者activity,由於activity中的onTouchEvent也返回到 super,所以事件消失,..具體看log輸出的過程和解釋
因為事件也在activity中,並沒有傳遞給子view 所以返回按鈕失效
下一個情境,讓我們的liearlayout中的onInterceptTouchEvent返回false,不攔截,那麼事件將會傳遞給子view,子view在去調用自己的dispatch方法去紛發,這樣事件就能被返回箭頭接受,可以正常關閉activity
我們看下log輸出,
由於onInterceptTouchevent返回了false,所以事件執行完他裡面的方法後就把事件傳遞給了子view,於是事件就從發源地activity 和linearlayout中的 dispatch 和 intercept 起作用,並沒有onTouchEvent的事情了,具體細節看log輸出描述,然後由於事件傳遞給了子view 所以 返回箭頭生效,這個方法返回false和返回super產生的效果是一模一樣的,這裡就不在了有興趣的可以輸出一下
到此為止我們activity中只有一個viewgroup的情境基本分析完畢了,然後我們想liearlayout中添加一個textview如
因為我們這裡加入的是最小單位的view就是view不能再添加額外的內容,我們手指觸控螢幕幕事件傳遞過程,有activity 到 liearlayout 在到view 在返回 linearlayout ,返回activity 直到消失,具體過程如下;
再來一個情境,這次我們讓childview中的dispatch 事件返回false,
筆者本來也是對這個傳遞有點模糊的,今天部落格寫到這裡我都能猜到列印結果了,由於textviewdispatch返回了false ,所以事件執行完dispatch down後直接把事假返回給父view linearlayout的onTouchEvent,由於onTouchEvent設定了touchlistener 所以後執行,然後就是父view也返回了super,所以事件傳遞給activity的onTouchEvent 由於activity的onTouchEvent也返回了super.所以事件消失,最後在activity中執行 move 和 up
然後我們看下列印結果;
寫到這裡,理解的事件傳遞在腦海裡的模糊情境已經有點透明了,還需要更多的實踐,文中可能有理解不到位的也請大神批正,到此我理解的事件傳遞在viewgroup 和view中全部結束,也感謝群裡nil的指點謝謝!
如果你看完還是對這個過程不是很理解,請自己類比情境列印log,因為我感覺沒有在比筆者更笨出身更貧寒的了,當你類比看log有點想吐甚至能猜到不同的傳回值會是什麼樣的傳遞情境,那麼你對事件傳遞的過程相比之前你的理解肯定有恍然大悟的!謝謝….