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