為什么要了解Android事件分發(fā)機制肺孵?
問題一:內外嵌套的滑動沖突問題
不知大家有沒有遇到過這樣的情況正卧,一個滾動的控件中再嵌套一個滾動的控件惯豆,發(fā)現(xiàn)當你要滾動里面的控件時池磁,外面的控件滾動了,里面的控件卻不滾動楷兽,或者框仔,你要想讓里面的控件滾動到底時,外面的控件才開始滾動.
問題二:方向滑動沖突問題
ListView的header放入一個左右滑動的banner或者說viewpager拄养,那么當手指在banner上下滑動時將無法促使外層ListView的滑動离斩,這就非常影響用戶的使用體驗了银舱。
當了解了View的事件分發(fā)機制,以上問題將不再是問題了跛梗。 我們就可以利用事件分發(fā)機制來制定我們想要的滾動規(guī)則寻馏。
默認的情況下,當手指點擊最中間的View1時核偿,觸發(fā)順序如下(自上往下):
EVENT_DOWN:
activity1 - dispatchTouchEvent
viewGroup1 - dispatchTouchEvent
viewGroup1 - onInterceptTouchEvent
view1 - dispatchTouchEvent
view1 - onTouchEvent
viewGroup1 - onTouchEvent
activity1 - onTouchEvent
EVENT_MOVE:
activity1 - dispatchTouchEvent
activity1 - onTouchEvent
EVENT_UP:
activity1 - dispatchTouchEvent
activity1 - onTouchEvent
1诚欠、為什么EVENT_MOVE和EVENT_UP僅僅在最外層的activity1傳遞,而沒有傳遞到viewGroup1和view1漾岳?
Android中事件分發(fā)機制中轰绵,如果內層的view都沒有消耗事件,事件默認由最外層View進行處理尼荆,也就是activity處理事件左腔。
2、什么時候view才算消費了事件捅儒?
第一種情況液样,view的clickable或者longClickable為true(普通view的clickable默認false);
第二種情況巧还,view設置了點擊監(jiān)聽或者長按監(jiān)聽鞭莽,因為通過源碼可以看到,setOnClickListener中調用了setClickable(true)麸祷;
第三種情況澎怒,setOnTouchListener中返回true,這種也是最常見的阶牍。在setOnTouchListener中處理事件喷面,然后返回true,那么該view的onTouchEvent將不會被執(zhí)行荸恕。
3乖酬、viewGroup中的onInterceptTouchEvent在實際應用中起到什么作用?
舉個例子融求,我們要自定義一個類似于listview的控件時咬像,自定義完畢后,在使用過程中生宛,發(fā)現(xiàn)我們自定義的listview控件中的item設置了button控件县昂,button控件clickable為true,默認消費了事件陷舅,那么只要我們的手指觸控在button上時倒彰,就不能對整個listview控件進行滑動了。
- 重寫onInterceptTouchEvent方法就起到作用了莱睁,當手指滑動距離大于一定距離d時待讳,我們就讓onInterceptTouchEvent返回true芒澜,阻止事件往下傳遞。(tips:上面的距離d可以通過
ViewConfigurationCompat.getScaledPagingTouchSlop(ViewConfiguration.get(context))獲却吹)- 但是痴晦,如果我們把item中的button替換成listview呢。琳彩。那么誊酌,上面我們重寫onInterceptTouchEvent之后,外層的listview攔截了事件以致于item中的listview無法滾動露乏。這個很好解決碧浊,ViewGroup中有一個requestDisallowInterceptTouchEvent(true)方法,可以發(fā)出一次“禁止下一個事件的攔截”的請求瘟仿,可以在我們的view的任何一個touch方法中調用view.getParent.requestDisallowInterceptTouchEvent(true)