編輯:關於Android編程
關於事件你應該知道的是
當一個事件產生後,他的傳遞過程遵循如下順序Activity > Window > View
事件來源於activity,activity假如你沒有重寫任何關於事件紛發的方法的話,他會把事件傳遞給window,window將事件傳遞給decorView
現在我們來看下假如我們在activity中重寫了dispatchEvent的方法是什麼樣的一個情況.
我們把activity中的dispatchTouchEvent 返回true
事件被activity的dispatchTouchEvent消耗掉,所以activity的
onTouchEvent方法得不到響應,我們看下log輸出
很明顯的能看出來,log只打印了dispatchTouchEvent中的相關方法,整個事件被dispatchTouchEvent消耗掉,並沒有傳遞到我們的window > decZ喎?/kf/ware/vc/" target="_blank" class="keylink">vclZpZXcgy/nT0M7SvefD5rXEt7W72Lz8vdPK3LK7tb3Kwrz+LMv50tS3tbvYsLTFpbXEteO798rCvP7SssO7yfrQpyw8L3A+DQo8cD7O0sPH1Nqw0WFjdGl2aXR51tC1xGRpc3BhdGNoVG91Y2hFdmVudLe1u9hmYWxzZb+0v7TKx8qyw7TH6b/2LCw8c3Ryb25nPtXi0rLKx87StcTSu7j20snOyrXjLMLpt7O088nxsO/Dpr3itPDSu8/CPC9zdHJvbmc+vs3Kx87SYWN0aXZpdHnW0LXEZGlzcGF0Y2hUb3VjaEV2ZW50t7W72MHLZmFsc2UsxMfDtMrCvP6x6ta+18XKwrz+w7vIy7SmwO0stMvKscrCvP61xLj51LTKx7TTYWN0aXZpdHnAtLXELMjnufvL+7a8sru53LXEu7As1eK49srCvP7S0b6tsrvE3Le1u9jL+7XEuLh2aWV3ICy1scewYWN0aXZpdHm1xG9uVG91Y2hFdmVudCgp0rLO3mxvZ8rks/YsxMfDtMrCvP7ExMDvyKXByz8/Pz88YnIgLz4NCjxpbWcgYWx0PQ=="這裡寫圖片描述" src="/uploadfile/Collfiles/20160401/20160401092456296.png" title="\" />
然後我們看下返回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,這裡以為linearlayout中dispatchonTouchEvent返回了true,事件在這裡終止了,所以我們的返回箭頭就接收不到事件,於是我們的返回按鈕就失效了.
第二個場景,我們讓linearlayout的dispatchonTouchEvent返回false,那麼這個觸摸事件將是一個怎麼樣的過程呢?
dispatchonTouchEvent.返回false,事件要被來自哪裡,就要被返回哪裡,假如我們的linearlayout還有父view ,那麼這個事件將返回給父view的onTouchEvent事件處理,如果來自activity,那麼將被activity的onTouchEvent處理,看下我們的log輸出;
![這裡寫圖片描述](http://img.blog.csdn.net/20160331173347685)
當我們點擊我們的返回箭頭的時候,因為事件從liearlayout中返回給了activity消費,所以子控件沒法接收到事件,所以點擊返回的箭頭也無法生效;
第三個場景,linearlayout中的onInterceptTouchEvent返回true,其他返回super,猜想,攔截事件返回true,那麼事件不會傳遞給子view,因為事件也在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有點想吐甚至能猜到不同的返回值會是什麼樣的傳遞場景,那麼你對事件傳遞的過程相比之前你的理解肯定有恍然大悟的!謝謝….
前言:Android提供了一些方便使用的組件:TextView等,但是很多時候,默認的組件不能滿足需要,因此,必需掌握“自定義組件”的能力。對於程
曾經有一個朋友問過我一個問題, 一張512*512 150KB PNG格式圖片和一張512*512 100KB 壓縮比是8的JPG格式的圖片,加載到內存中,也
有時候我們需要在游戲或應用中用一些符合我們樣式的提示框(AlertDialog),以下是我在開發一個小游戲中總結出來的.希望對大家有用.先上效果圖:下面是用到的背景圖或按
一.滑動界面:第一次啟動時除了啟動動畫外,可能還有著滑動功能介紹界面,現在記錄一下這種界面的實現方式,接著上篇啟動動畫之後的效果附加上。效果圖: 界面:&nb