這里通過一個(gè)自定義view的例子來看事件分發(fā)在自定義view中的使用,其實(shí)大部分的Android框架下的事件分發(fā)的也都差不多的樣子,拋磚引玉,我自己做一個(gè)記錄,如果能幫到有需要的人那就更上一層樓。
先來看一個(gè)微信發(fā)送語音的效果圖:

關(guān)于事件分發(fā)我們其實(shí)耳熟能詳,可以通過一段非常有名的偽代碼來大致了解:
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
boolean consume = false;
if(onInterceptTouchEvent(ev)){
consume = onTouchEvent(ev);
}else {
consume = child.dispatchTouchEvent(ev);
}
return consume;
}
事件都是從一個(gè)DOWN開始,中間經(jīng)過一堆MOVE,到一個(gè)UP結(jié)束(先拋開CANCEL的情況)。
事件流向畫了半天,感覺也沒有人家畫的好,可以參考 這里 ,很清晰,忘記了的或者細(xì)節(jié)不清楚模糊了的可以移步去復(fù)習(xí)一下。
我們的需求是點(diǎn)擊發(fā)送按鈕后顯示浮層view,相當(dāng)于事件先由發(fā)送按鈕處理,等浮層view顯示后再交由浮層view處理,這個(gè)事件的流向很清晰,那應(yīng)該怎么做呢。
那最簡單的view的層級結(jié)構(gòu)就是發(fā)送按鈕和浮層view處在同一層級,那一個(gè)問題,事件能否在parent什么都不做的情況下實(shí)現(xiàn)事件在同級別view之間的轉(zhuǎn)移呢?
肯定是不可以或者說沒有必要的,最好的方式還是通過parent來做分發(fā),由parent的決定此時(shí)到底是需要把事件交給發(fā)送按鈕還是浮層view。
所以層級結(jié)構(gòu)上:
<?xml version="1.0" encoding="utf-8"?>
<!-- parent, 來控制事件的分發(fā) -->
<com.yocn.af.view.widget.WeChatParentViewGroup
android:id="@+id/wechat_root"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/ll_option"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_alignParentBottom="true">
<!-- 發(fā)送按鈕view -->
<com.yocn.af.view.widget.WeChatVoiceTextView
android:id="@+id/tv_voice"
android:layout_width="0dp"
android:layout_height="match_parent"
android:gravity="center"
android:text="按住 說話"/>
</LinearLayout>
<!-- 點(diǎn)擊后需要顯示的浮層view -->
<com.yocn.af.view.widget.WeChatVoiceView
android:id="@+id/voice_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/half"
android:visibility="gone" />
</com.yocn.af.view.widget.WeChatParentViewGroup>
我們梳理一下思路,需要做的就是:
- 什么都沒做時(shí)
ParentViewGroup的onInterceptTouchEvent要返回false,使得事件能順利的從ParentViewGroup傳遞到VoiceTextView(發(fā)送按鈕) - 點(diǎn)擊到
VoiceTextView(發(fā)送按鈕)時(shí),發(fā)送按鈕的dispatchTouchEvent返回true,處理DOWN事件并告訴parent需要顯示WeChatVoiceView(浮層view) - parent接收到需要顯示浮層view的命令,顯示浮層view并且
onInterceptTouchEvent返回true,表示事件我parent來處理,這時(shí)VoiceTextView(發(fā)送按鈕)會(huì)收到一個(gè)CANCEL事件并且不會(huì)繼續(xù)接受MOVE事件。 - parent來分發(fā)事件,在
WeChatVoiceView(浮層view)顯示出來之后直接將后續(xù)的MOVE事件交給WeChatVoiceView(浮層view)處理,當(dāng)然浮層view的onInterceptTouchEvent需要返回true,會(huì)回調(diào)到浮層view的onTouchEvent,直接做對應(yīng)的動(dòng)畫或者手勢操作。 - 當(dāng)然不要忘記在parent收到ACTION_UP的時(shí)候?qū)?code>浮層view置為不可見,因?yàn)槭录怯蓀arent分發(fā)給
浮層view的,當(dāng)然parent可以一直拿到事件。
至此,整個(gè)事件分發(fā)的流程就結(jié)束了。
附上代碼地址WeChatSendVoice