Android事件分發
時間:2016-12-21作者:華清遠見
1、 引言:Android如此受歡迎,其優秀的交互性功不可沒,優秀的事件分發機制在交互性中起到了重要的作用。想做出有良好交互性的應用,深入了解事件分發機制是十分必要的。 2、 View和ViewGroup:Android的UI界面都是由View和ViewGroup的派生類組成的,其中View是UI組件的基類,而ViewGroup是容納這些組件的容器,其本身也是ViewGroup的派生類。 3、 事件:簡單來時,事件就是當用戶的手觸摸到屏幕上時,Android所做出的一系列響應,比如點擊按鈕,滑動屏幕等。 4、 意義:其實Android的各個控件已經提供了完善的事件分發機制,比如我們在點擊按鈕的時候會觸發按鈕的監聽,滑動一個listview時也會自動的移動,既然Android自身的事件分發機制已經如此完善,那么我們了解它會在我們項目開發時有什么好處呢?這里我想說,Android再完善的事件分發機制也無法滿足我們在項目中千變萬化的UI設計需求,我們了解事件分發機制,就是為了讓我們能夠更加靈活的做出各種UI效果。比如我想在做一個抽屜效果,當然大家會想到使用DrawerLayout,那么在抽屜收起的時候我想能夠對屏幕上的各個控件正常操作,但是當抽屜拉出時我又想屏蔽掉被抽屜遮擋住的控件。做過抽屜效果的同學都知道,使用Android的DrawerLayout,要么全時的屏幕掉遮擋的控件,要么就根本無法屏蔽,做不到隨心控制,這時就需要我們自定義DrawerLayout,并且靈活的編寫自定義DrawerLayout中的事件分發! 5、 事件分發中的三個函數:dispatchTouchEvent,onInterceptTouchEvent,onTouchEvent。網絡上關于這三個函數的描述非常的多而且全面,在這里我就不多解釋了,這里我只從應用的角度來對三個函數做個總結; dispatchTouchEvent兄弟節點間的事件攔截,onInterceptTouchEvent父子節點間的事件攔截,onTouchEvent本節點對事件的消費。簡單的一個總結,相信大家能夠對這三個函數有個大概的了解,其實我們對事件分發的控制無非就是“攔截”和“分發”。以剛才的抽屜為例,當抽屜拉出時攔截事件的分發,當抽屜收回時不攔截事件的分發。 6、 事件分發的流程:
這幅圖描述了一個UI的樹形結構,其中ViewGroup1是Viewgroup2、View2、View3的父節點,Viewgroup2是View1的父節點。事件分發的流程是Activity->ViewGroup1->ViewGroup2->View1->View2->View3;基本的原則就當一個節點獲得到事件后,先向子節點分發,然后再向兄弟節點分發,整個過程中任何一個節點消費了事件,那么分發停止。 7、 實例分析:MyLayout和Mylayout2都繼承RelativeLayout,并且重寫其中的三個事件函數;MyView繼承ImageView,重寫其中的onTouchEvent。
MyLayout代碼如下:
MyLayout2代碼如下:
MyView代碼如下:
MainActivity代碼如下:
布局文件如下:
我們注意到,事件的三個函數都有一個boolean的返回值,dispatchTouchEvent和onInterceptTouchEvent返回true時表示要攔截,false表示不攔截;onTouchEvent返回true表示要消費,false表示不消費。既然了解了返回值的作用,那么大家應該可以想到,我們對事件分發的控制就是通過控制返回值來實現的。當前布局是MyLayout2遮擋MyLayout,為兄弟節點;MyView為MyLayout2的子節點。以當前布局為前提,我們來進行幾個實驗. 實驗1:MyLayout2的dispatchTouchEvent返回true,onInterceptTouchEvent返回true,onTouchEvent返回true;MyView和MyLayout隨意。 點擊MyLayout2和MyLayout重合部分
此時只有MyLayout2獲得到了響應。 實驗2:MyLayout2不變,將MyLayout的三個事件函數返回值全部定義為true。 點擊MyLayout2和MyLayout重合部分
點擊MyLayout不被遮擋的部分
對比發現MyLayout雖然有獲得響應的能力,但是由于MyLayout2進行了兄弟節點的攔截,所以在點擊MyLayout2和MyLayout重合部分時MyLayout無法獲得事件的響應。 通過實驗1和實驗2我們可以看到dispatchTouchEvent對兄弟節點的事件攔截能力。 實驗3:將MyView的onTouchEvent返回值定義為true,MyLayout2保持不變,點擊MyView。
結果發現MyView雖然onTouchEvent返回true表示想要得到事件響應,但是卻并沒有獲得到響應。 實驗4: MyLayout2的onInterceptTouchEvent返回值定義為false,MyView不變,點擊MyView.
發現MyView成功獲得到響應,實驗3、4證明了onInterceptTouchEvent對父子節點的攔截能力。 8、總結: 需要聲明的是,任何事件函數都會無條件的獲得到MotionEvent.ACTION_DOWN 的事件,也就是用戶手觸摸的屏幕時的事件。 以上通過4個簡單的小實驗介紹了一下事件的攔截和分發的基本用法,也給大家提供了一些分析此類問題的思路,有了本次實驗作為基礎,相信大家在學習Android事件分發相關知識的時候將不會再束手無策。 發表評論
|