Android事件分發
時(shi)間:2016-12-21作者:華清遠見
1、 引言:Android如此受歡迎,其優(you)秀的(de)交(jiao)互性(xing)功不可沒,優(you)秀的(de)事(shi)件分(fen)發(fa)機制在(zai)交(jiao)互性(xing)中起(qi)到了(le)重(zhong)要的(de)作(zuo)用。想(xiang)做出有(you)良好交(jiao)互性(xing)的(de)應用,深入(ru)了(le)解事(shi)件分(fen)發(fa)機制是(shi)十(shi)分(fen)必要的(de)。 2、 View和(he)ViewGroup:Android的(de)(de)UI界(jie)面(mian)都(dou)是(shi)由View和(he)ViewGroup的(de)(de)派生類組成的(de)(de),其中View是(shi)UI組件的(de)(de)基類,而ViewGroup是(shi)容(rong)納(na)這些(xie)組件的(de)(de)容(rong)器,其本(ben)身也是(shi)ViewGroup的(de)(de)派生類。 3、 事件:簡(jian)單(dan)來時,事件就(jiu)是(shi)當用戶的手觸(chu)摸到屏幕(mu)上時,Android所做出的一系列響應(ying),比如點擊按鈕,滑動屏幕(mu)等。 4、 意義:其實(shi)Android的(de)各個(ge)(ge)控(kong)件(jian)已經提供(gong)了完(wan)善(shan)的(de)事件(jian)分發機(ji)(ji)制(zhi),比如我(wo)(wo)們在點(dian)擊(ji)按(an)鈕(niu)的(de)時(shi)(shi)(shi)候會觸發按(an)鈕(niu)的(de)監(jian)聽,滑動一(yi)(yi)個(ge)(ge)listview時(shi)(shi)(shi)也(ye)會自(zi)動的(de)移動,既然Android自(zi)身的(de)事件(jian)分發機(ji)(ji)制(zhi)已經如此完(wan)善(shan),那么(me)我(wo)(wo)們了解(jie)它會在我(wo)(wo)們項(xiang)目開發時(shi)(shi)(shi)有什么(me)好處呢?這里(li)我(wo)(wo)想(xiang)說,Android再完(wan)善(shan)的(de)事件(jian)分發機(ji)(ji)制(zhi)也(ye)無(wu)法(fa)滿足我(wo)(wo)們在項(xiang)目中千變萬化的(de)UI設(she)計需求(qiu),我(wo)(wo)們了解(jie)事件(jian)分發機(ji)(ji)制(zhi),就是為(wei)了讓我(wo)(wo)們能(neng)夠更加(jia)靈活的(de)做(zuo)出(chu)各種UI效果。比如我(wo)(wo)想(xiang)在做(zuo)一(yi)(yi)個(ge)(ge)抽(chou)(chou)(chou)屜(ti)(ti)(ti)效果,當(dang)然大家會想(xiang)到使用(yong)DrawerLayout,那么(me)在抽(chou)(chou)(chou)屜(ti)(ti)(ti)收起的(de)時(shi)(shi)(shi)候我(wo)(wo)想(xiang)能(neng)夠對屏(ping)(ping)幕(mu)上(shang)的(de)各個(ge)(ge)控(kong)件(jian)正(zheng)常(chang)操作,但是當(dang)抽(chou)(chou)(chou)屜(ti)(ti)(ti)拉(la)出(chu)時(shi)(shi)(shi)我(wo)(wo)又想(xiang)屏(ping)(ping)蔽掉(diao)被抽(chou)(chou)(chou)屜(ti)(ti)(ti)遮(zhe)擋(dang)住的(de)控(kong)件(jian)。做(zuo)過(guo)抽(chou)(chou)(chou)屜(ti)(ti)(ti)效果的(de)同學都知道,使用(yong)Android的(de)DrawerLayout,要么(me)全時(shi)(shi)(shi)的(de)屏(ping)(ping)幕(mu)掉(diao)遮(zhe)擋(dang)的(de)控(kong)件(jian),要么(me)就根(gen)本無(wu)法(fa)屏(ping)(ping)蔽,做(zuo)不到隨心控(kong)制(zhi),這時(shi)(shi)(shi)就需要我(wo)(wo)們自(zi)定義DrawerLayout,并且靈活的(de)編寫自(zi)定義DrawerLayout中的(de)事件(jian)分發! 5、 事(shi)(shi)件(jian)(jian)(jian)分(fen)(fen)(fen)發中(zhong)的(de)(de)(de)(de)三(san)個(ge)(ge)(ge)函(han)數:dispatchTouchEvent,onInterceptTouchEvent,onTouchEvent。網絡上關于這(zhe)(zhe)(zhe)三(san)個(ge)(ge)(ge)函(han)數的(de)(de)(de)(de)描述非(fei)常的(de)(de)(de)(de)多而且全(quan)面(mian),在(zai)這(zhe)(zhe)(zhe)里我(wo)就不多解釋了(le),這(zhe)(zhe)(zhe)里我(wo)只從(cong)應用(yong)的(de)(de)(de)(de)角度來對(dui)三(san)個(ge)(ge)(ge)函(han)數做個(ge)(ge)(ge)總結(jie)(jie); dispatchTouchEvent兄弟節點間的(de)(de)(de)(de)事(shi)(shi)件(jian)(jian)(jian)攔(lan)(lan)截(jie),onInterceptTouchEvent父子節點間的(de)(de)(de)(de)事(shi)(shi)件(jian)(jian)(jian)攔(lan)(lan)截(jie),onTouchEvent本節點對(dui)事(shi)(shi)件(jian)(jian)(jian)的(de)(de)(de)(de)消(xiao)費。簡單的(de)(de)(de)(de)一個(ge)(ge)(ge)總結(jie)(jie),相信大家能夠對(dui)這(zhe)(zhe)(zhe)三(san)個(ge)(ge)(ge)函(han)數有個(ge)(ge)(ge)大概(gai)的(de)(de)(de)(de)了(le)解,其實我(wo)們對(dui)事(shi)(shi)件(jian)(jian)(jian)分(fen)(fen)(fen)發的(de)(de)(de)(de)控(kong)制無非(fei)就是“攔(lan)(lan)截(jie)”和“分(fen)(fen)(fen)發”。以剛才的(de)(de)(de)(de)抽屜(ti)為(wei)例,當抽屜(ti)拉出時攔(lan)(lan)截(jie)事(shi)(shi)件(jian)(jian)(jian)的(de)(de)(de)(de)分(fen)(fen)(fen)發,當抽屜(ti)收回時不攔(lan)(lan)截(jie)事(shi)(shi)件(jian)(jian)(jian)的(de)(de)(de)(de)分(fen)(fen)(fen)發。 6、 事件分發(fa)的流(liu)程:
這(zhe)幅圖描述了一(yi)個UI的樹形結(jie)構,其中ViewGroup1是Viewgroup2、View2、View3的父(fu)(fu)節(jie)點,Viewgroup2是View1的父(fu)(fu)節(jie)點。事件(jian)分發的流程(cheng)是Activity->ViewGroup1->ViewGroup2->View1->View2->View3;基本的原則就當一(yi)個節(jie)點獲得到事件(jian)后(hou),先向子節(jie)點分發,然后(hou)再向兄弟節(jie)點分發,整個過程(cheng)中任何(he)一(yi)個節(jie)點消費了事件(jian),那么分發停止。 7、 實(shi)例分析:MyLayout和Mylayout2都繼承RelativeLayout,并且重(zhong)寫其中(zhong)的三個事件函數(shu);MyView繼承ImageView,重(zhong)寫其中(zhong)的onTouchEvent。
MyLayout代碼(ma)如下(xia):
MyLayout2代碼如(ru)下:
MyView代碼(ma)如下:
MainActivity代碼如(ru)下:
布局(ju)文件(jian)如下:
我(wo)們(men)注意到,事件(jian)的(de)三個(ge)函數都有一(yi)個(ge)boolean的(de)返回值,dispatchTouchEvent和onInterceptTouchEvent返回true時表(biao)示(shi)要攔截(jie),false表(biao)示(shi)不攔截(jie);onTouchEvent返回true表(biao)示(shi)要消費,false表(biao)示(shi)不消費。既(ji)然了(le)解(jie)了(le)返回值的(de)作用,那么大家應該可以想(xiang)到,我(wo)們(men)對事件(jian)分發的(de)控制(zhi)就是(shi)通過控制(zhi)返回值來實現的(de)。當前(qian)(qian)布局是(shi)MyLayout2遮(zhe)擋MyLayout,為(wei)(wei)兄弟節點;MyView為(wei)(wei)MyLayout2的(de)子節點。以當前(qian)(qian)布局為(wei)(wei)前(qian)(qian)提(ti),我(wo)們(men)來進(jin)行幾個(ge)實驗. 實驗(yan)1:MyLayout2的dispatchTouchEvent返回(hui)true,onInterceptTouchEvent返回(hui)true,onTouchEvent返回(hui)true;MyView和(he)MyLayout隨(sui)意。 點擊MyLayout2和MyLayout重(zhong)合部分
此時只有MyLayout2獲得到了響應。 實驗2:MyLayout2不(bu)變,將MyLayout的三個事件函(han)數返回(hui)值全部(bu)定義為true。 點擊MyLayout2和(he)MyLayout重合部分
點(dian)擊MyLayout不被(bei)遮擋的部分(fen)
對比(bi)發現MyLayout雖然有獲得(de)響(xiang)應(ying)的(de)能力,但是(shi)由(you)于(yu)MyLayout2進行了兄(xiong)弟節點(dian)的(de)攔截(jie),所以在點(dian)擊MyLayout2和(he)MyLayout重合(he)部分時(shi)MyLayout無法獲得(de)事件的(de)響(xiang)應(ying)。 通(tong)過(guo)實驗1和實驗2我們可以看到dispatchTouchEvent對兄弟節點的事件攔截能力。 實驗3:將MyView的onTouchEvent返(fan)回值定義為true,MyLayout2保持不變,點擊MyView。
結果發現MyView雖然onTouchEvent返回true表(biao)示想要得(de)到事件響應,但是(shi)卻并(bing)沒有獲得(de)到響應。 實驗4: MyLayout2的onInterceptTouchEvent返回(hui)值定義為false,MyView不變,點擊MyView.
發現MyView成功獲得到響應,實驗(yan)3、4證明(ming)了onInterceptTouchEvent對(dui)父子節點的攔截能力。 8、總結: 需要聲明的(de)是,任何事(shi)件函數(shu)都會無(wu)條件的(de)獲得到MotionEvent.ACTION_DOWN 的(de)事(shi)件,也就是用戶手觸摸的(de)屏幕時的(de)事(shi)件。 以上(shang)通(tong)過(guo)4個簡單的小(xiao)實驗(yan)介(jie)紹(shao)了(le)一下(xia)事件的攔(lan)截(jie)和分發(fa)的基本(ben)(ben)用法,也(ye)給大(da)家提供(gong)了(le)一些分析此類(lei)問題的思路,有了(le)本(ben)(ben)次實驗(yan)作為基礎,相信大(da)家在學(xue)習Android事件分發(fa)相關(guan)知識(shi)的時候將不會再束手(shou)無(wu)策。 發表評論
|
關注華清遠見
關注創客學院