说一说Android事件分发中的requestDisallowInterceptTouchEvent
前言
我們知道在事件分發過程中是存在一個攔截機制的
onInterceptTouchEvent當它返回true則不向下分發事件,否則向下分發。
但是在這個過程中,還有一個參與者:requestDisallowInterceptTouchEvent,這個函數直接影響事件的攔截。我們今天就來說一說這個這個函數是如何影響事件分發的。
源碼分析
我們先看看這個函數的源碼
@Override public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {// We're already in this state, assume our ancestors are tooreturn;}if (disallowIntercept) {mGroupFlags |= FLAG_DISALLOW_INTERCEPT;} else {mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;}// Pass it up to our parentif (mParent != null) {mParent.requestDisallowInterceptTouchEvent(disallowIntercept);} }可以看到它改變了一個開關FLAG_DISALLOW_INTERCEPT,同時調用其parent的函數。
那么這個開關有什么用?
在ViewGroup的dispatchTouchEvent函數開頭有這樣一段代碼:
final boolean intercepted; if (actionMasked == MotionEvent.ACTION_DOWN|| mFirstTouchTarget != null) {final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;if (!disallowIntercept) {intercepted = onInterceptTouchEvent(ev);ev.setAction(action); // restore action in case it was changed} else {intercepted = false;} } else {// There are no touch targets and this action is not an initial down// so this view group continues to intercept touches.intercepted = true; }先來看判斷邏輯,當是down事件或者mFirstTouchTarget不為空,則進入一個代碼段;否者攔截設置為true。
我們知道down事件分發過程中,如果有子view消費事件,則賦值給mFirstTouchTarget,后續事件會直接分發給mFirstTouchTarget
這里也可以看出,如果有子View消費了down事件,即mFirstTouchTarget不為空,所以后續事件還會檢查攔截。
所以上面就可以理解了,如果down事件中沒有子view消費事件,那么后續事件的攔截都為true。所以后續事件不會再遍歷子View。
下面再看if代碼段
一開始就使用了FLAG_DISALLOW_INTERCEPT開關,即disallowIntercept
當disallowIntercept為true,則不攔截;否者判斷onInterceptTouchEvent
所以簡單來說requestDisallowInterceptTouchEvent設置為true可以跳過onInterceptTouchEvent,不攔截事件。
而且因為requestDisallowInterceptTouchEvent又調用了parent的函數,所以所有層次的父view都不再攔截。
所以requestDisallowInterceptTouchEvent的功能是讓這個view及上面的所有父view都放開攔截,即使onInterceptTouchEvent為true。
所以我們一般如下使用
view.getParent().requestDisallowInterceptTouchEvent(true);這樣view的所有層次的父view都不會攔截事件了。
擴展思考
下面讓我們再深入想想。上面這種的情況是在touch事件發生前設置onInterceptTouchEvent,也是我們一般的用法。但是如果事件發生過程中調用這個函數呢?
比如在view的onTouch的某個事件中使用
getParent().requestDisallowInterceptTouchEvent(true)當事件開始分發時,down事件進入父view的dispatchTouchEvent時,這是子view還未得到事件,所以沒有設置requestDisallowInterceptTouchEvent。
這時如果父view的onInterceptTouchEvent返回true,即攔截的話,事件則不會分發給子view了,所以requestDisallowInterceptTouchEvent永遠不會執行,子view則無法得到事件。
但是如果父view的onInterceptTouchEvent返回false,即不攔截的話,事件就可以分發到子view,requestDisallowInterceptTouchEvent執行,之后的事件都會跳過父view的onInterceptTouchEvent的判斷
例如父view的onInterceptTouchEvent代碼如下
public boolean onInterceptTouchEvent(MotionEvent ev) {switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:return false;case MotionEvent.ACTION_MOVE: return true;case MotionEvent.ACTION_UP:return true;default:break;}return false; }down事件不進行攔截,但是攔截了move和up事件。
如果子view的onTouch的down事件中使用
總結
以上是生活随笔為你收集整理的说一说Android事件分发中的requestDisallowInterceptTouchEvent的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 解决Webview加载不完全导致部分js
- 下一篇: Android事件分发机制之ACTION