在安卓開發中會時常碰到滑動沖突的情況,比如有一個水平滑動的 ViewPager 里面有 Fragment,
Fragment 里面有水平滑動的 ViewGroup,當你的手指在屏幕水平滑動時,就會發生沖突,那怎么
解決這種沖突呢,首先開發者需要對 Activity、ViewGroup、View 的事件傳遞機制有個很好的認識。
觸摸事件的類型
觸摸事件對應的是MotionEvent類,事件類型主要有三種:
- ACTION_DOWN: 用戶手指按下屏幕,標志著一次觸摸事件開始。
- ACTION_MOVE: 用戶手指按下屏幕之后,在松開之前,如果滑動的距離超過了一定值,則會
被判定為 ACITON_MOVE 操作。 - ACTION_UP: 用戶手指離開屏幕,標志著一次完整觸摸事件結束。
一次屏幕觸摸操作,一定會產生 ACTION_DOWN
和 ACTION_UP
兩種事件,如果用戶按下
之后手指右移動一定的距離,則會發生 ACTION_MOVE
事件,如果只是點了一下,那么則不
會發生。
觸摸事件傳遞
觸摸事件的傳遞有三個階段:
分發(dispatch): 所有的事件都是通過這個方法分發,對應的方法原型為
public boolean dispatchTouchEvent(MotionEvent event)
如果方法返回true,則當前視圖消費事件,不在分發,super.dispatchTouchEvent 表示繼續
分發事件,如果當前視圖是 ViewGroup,則會調用 interceptTouchEvent攔截(intercept): 這個方法中 ViewGroup 中,顧名思義,就是對觸摸事件的攔截,方法原型為
public boolean onInterceptHoverEvent(MotionEvent event)
- 消費(consume: 事件最終需要被消費,對應的方法原型為
public boolean onTouchEvent(MotionEvent event)
如果方法返回 true,則說明當前視圖可以消費事件,不會再向上傳遞事件;返回值為 false,則
表示消費事件,繼而向上層父視圖傳遞事件,讓父視圖來處理。
觸摸事件傳遞的三個角色:
- Activity: 擁有 dispatchTouchEvent 和 onTouchEvent 兩個方法。
- ViewGroup: 擁有 dispatchTouchEvent 、onInterceptTouchEvent 和 onTouchEvent 三個方法。
- View: 擁有 dispatchTouchEvnet 和 onTouchEvent 兩個方法。
觸摸事件傳遞三種類型
- View 不消費事件
DOWN 事件不消費,onTouchEvnet 返回 false,父視圖 onTouchEvent 方法執行,接下來的
MOVE、UP 事件也不會再傳遞給該 View,而是由消費了 DOWN 事件的父視圖接收
View 不消費事件
- View 消費事件
View 消費了 DOWN 事件,onTouchEvent 返回 true,父視圖的 onTouchEvent 方法不會被執行,
接下來的 MOVE、UP 事件繼續傳遞給該 View,除非傳遞過程被攔截

-
事件被攔截
DOWN 事件被 View 消費了,但接下來的 MOVE、up 事件被攔截了,所以 View 無法消費整套觸摸事件
事件被攔截