ViewGroup/View的事件分發機制(3)(Touch,down,move,up)
> View的事件傳遞機制的11個結論:
1. 同一個事件序列是從手指觸控螢幕的那一刻起,到手指離開螢幕那一刻結束,這個過程中所產生的一系列事件。這個事件序列以down事件開始,中間含有數量不定的move事件,最終以up事件結束。
2. 一個事件序列只能被一個View攔截且消耗,不過通過事件代理TouchDelegate,可以將onTouchEvent強行傳遞給其他View處理。
3. 某個View一旦決定攔截,那麼這一事件序列就都只能由它來處理
4. 某個View一旦開始處理事件,如果不消耗ACTION_DOWN事件(onTouchEvent返回了false),那麼事件會重新交給它的父元素處理,即父元素的onTouchEvent會被呼叫。
5. 如果View不消耗除ACTION_DOWN以外的事件,那麼這個點選事件會消失,此時父元素的onTouchEvent並不會呼叫,並且當前View可以持續收到後續的事件,最終這些消失的事件會傳遞到Activity。
6. ViewGroup預設不攔截任何事件。Android原始碼中ViewGroup的onInterceptTouchEvent方法預設返回false。
7. View沒有onIntercepteTouchEvent方法,一旦有點選事件傳遞給它,那麼它的onTouchEvent方法就會被呼叫。
8. View的onTouchEvent預設都不會消耗事件(返回false),除非它是可點選的(clickable和longClickable有一個為true)。View的longClickable預設都為false,clickable要分情況看,比如Button預設為true,TextView預設為false。
9. View的enable屬性不影響onTouchEvent的預設返回值。哪怕一個View是disable狀態,只要它的clickable或者longClickable有一個為true,那麼它的onTouchEvent就返回true。
10. onClick會發生的前提是當前View是可點選的,並且它受到down和up的事件。
11. 事件傳遞是由外向內的,即事件總是先傳遞給父元素,然後再由父元素分發給子View,通過requestDisallowInterceptTouchEvent方法就可以在子元素中干擾父元素的事件分發過程,但ACTION_DOWN事件除外。
> Activity,View與ViewGroup的事件分發與事件攔截:
1.事件從Activity.dispatchTouchEvent()開始傳遞,只要沒有被停止或攔截,從最上層的View(ViewGroup)開始一直往下(子View)傳遞。子View 可以通過onTouchEvent()對事件進行處理。
2.事件由父View(ViewGroup)傳遞給子View,ViewGroup 可以通過onInterceptTouchEvent()對事件做攔截,停止其往下傳遞。
3.如果事件從上往下傳遞過程中一直沒有被停止,且最底層子View 沒有消費事件,事件會反向往上傳遞,這時父View(ViewGroup)可以進行消費,如果還是沒有被消費的話,最後會到Activity 的onTouchEvent()函式。
4.如果View 沒有對ACTION_DOWN 進行消費,之後的其他事件不會傳遞過來。
5.OnTouchListener 優先於onTouchEvent()對事件進行消費。
> 事件分發順序
View中onTouch,onTouchEvent和onClick的執行順序: onTouch->onTouchEvent->onClick
-- View的事件的分發機制由三個重要方法來共同完成:dispatchTouchEvent、onInterceptTouchEvent和onTouchEvent
1.事件分發:public boolean dispatchTouchEvent(MotionEvent ev)
用來進行事件的分發。如果事件能夠傳遞給當前View,那麼此方法一定會被呼叫,返回結果受當前View的onTouchEvent和下級View的DispatchTouchEvent方法的影響,表示是否消耗當前事件。
2.事件攔截:public boolean onInterceptTouchEvent(MotionEvent event)
在上述方法內部呼叫,用來判斷是否攔截某個事件,如果當前View攔截了某個事件,那麼在同一個事件序列當中,此方法不會被再次呼叫,返回結果表示是否攔截當前事件。
3.事件響應:public boolean onTouchEvent(MotionEvent event)
在dispatchTouchEvent方法中呼叫,用來處理點選事件,返回結果表示是否消耗當前事件,如果不消耗,則在同一個事件序列中,當前View無法再次接收到事件。
-- 三者的關係可以總結為如下虛擬碼:
public boolean dispatchTouchEvent(MotionEvent ev) {
boolean consume = false;
if (onInterceptTouchEvent(ev)) {
consume = onTouchEvent(ev);
} else {
consume = child.dispatchTouchEvent(ev);
}
return consume;
}
> 事件分發原理
事件型別分為ACTION_DOWN, ACTION_UP, ACTION_MOVE, ACTION_POINTER_DOWN, ACTION_POINTER_UP, ACTION_CANCEL,每個事件都是以ACTION_DOWN開始ACTION_UP結束。
對事件的處理包括三類,分別為傳遞——dispatchTouchEvent()函式;攔截——onInterceptTouchEvent()函式;消費——onTouchEvent()函式和OnTouchListener()。
ViewGroup的相關事件有三個:onInterceptTouchEvent、dispatchTouchEvent、onTouchEvent。View的相關事件只有兩個:dispatchTouchEvent、onTouchEvent。
事件序列為:ACTION_DOWN-->ACTION_MOVE-->ACTION-->...->ACTION_UP事件。
1)android對事件分發的順序為:Activity-->PhoneWindow->DecorView->yourView;
2)android控制元件對事件處理的優先順序:onTouch>onTouchEvent>onClick
-- 在分析ViewGroup分發事件之前還得說兩結論:
1)ViewGroup永遠不會對攔截,因為他的onInterceptTouchEvent(MotionEvent ev)始終返回的是false!這樣DecorView對到來的事件MotionEvent就只有分發到子View並由子View進行攔截和處理此事件了.
2)View包括直接繼承於View的子類因為其父類View沒有onInterceptTouchEvent方法,所以沒法對事件進行攔截,如果這種View獲取到了事件,那麼就會執行onTouchEvent方法(當然這也是有條件的,這個前提條件在對下面onTouch方法作用的時候會有說明)。
requestDisallowInterceptTouchEvent(boolean disallowIntercept )
//當前View干預其父View對後續事件的分發
mParent.requestDisallowInterceptTouchEvent(disallowIntercept);
我們是可以通過讓target呼叫requestDisallowInterceptTouchEvent方法來干預父類關於事件分發過程。或者在在適當的情況下讓target父View的onInterceptEvent返回true或者false,來解決滑動問題事件的衝突問題。當然在down事件之後的後續事件還是會先由父View進行分發攔截,也即是說文章開頭所說的事件序列中把每一個事件單獨來看的話,都會由父View來進行攔截和分發的,只不過到後續事件到傳到target的時候直接進行處理而少了攔截的過程而已,因為在父類查詢target的時候已經攔截過一次,這點很重要,也是解決滑動衝突的關鍵點,比如滑動的時候根據合適的時機來判斷是否讓父View進行事件攔截和處理。
-- 五個函式的大致執行順序如下:
1.dispatchTouchEvent()
2.onInterceptTouchEvent()
3.onTouch()
4.onTouchEvent()
5.onClick()
6.onLongClick()
> 事件分發與事件攔截
Android ViewGroup事件分發機制- http://blog.csdn.net/lmj623565791/article/details/39102591/
ViewGroup的相關事件有三個:onInterceptTouchEvent、dispatchTouchEvent、onTouchEvent。View的相關事件只有兩個:dispatchTouchEvent、onTouchEvent。
事件分發:public boolean dispatchTouchEvent(MotionEvent ev)
事件攔截:public boolean onInterceptTouchEvent(MotionEvent ev)
-- ViewGroup重寫了以下三個方法:
public class CustomViewGroup extends ViewGroup {
public CustomViewGroup(Context context) {
super(context);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.d("desaco", "ViewGroupA dispatchTouchEvent");
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.d("desaco", "ViewGroupA onInterceptTouchEvent");
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.d("desaco", "ViewGroupA onTouchEvent");
return super.onTouchEvent(event);
}
@Override
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
Log.e("desaco", "requestDisallowInterceptTouchEvent ");
super.requestDisallowInterceptTouchEvent(disallowIntercept);
}
@Override
protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
}
}
-- View重寫了以下兩個方法:
public class CustomView extends View {
public CustomView(Context context) {
super(context);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.d("desaco", "View onTouchEvent");
return super.onTouchEvent(event);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
Log.d("desaco", "View dispatchTouchEvent");
return super.dispatchTouchEvent(event);
}
}
-- Android ViewGroup事件分發機制- http://blog.csdn.net/lmj623565791/article/details/39102591/
如果ViewGroup的onInterceptTouchEvent(ev) 當ACTION_MOVE時return true ,即攔截了子View的MOVE以及UP事件;
此時子View希望依然能夠響應MOVE和UP時該咋辦呢?getParent().requestDisallowInterceptTouchEvent(true); 這樣即使ViewGroup在MOVE的時候return true,子View依然可以捕獲到MOVE以及UP事件。
@Override
public boolean dispatchTouchEvent(MotionEvent event)
{
getParent().requestDisallowInterceptTouchEvent(true);
int action = event.getAction();
switch (action)
{
case MotionEvent.ACTION_DOWN:
Log.e(TAG, "dispatchTouchEvent ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e(TAG, "dispatchTouchEvent ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e(TAG, "dispatchTouchEvent ACTION_UP");
break;
default:
break;
}
return super.dispatchTouchEvent(event);
}
View結構圖: View事件分發流程圖:
相關文章
- ViewGroup/View的事件分發機制(1)(Touch,down,move,up)View事件
- ViewGroup/View的事件分發機制(2)(Touch,down,move,up)View事件
- Android ViewGroup事件分發機制AndroidView事件
- View事件分發機制View事件
- 探索View的事件分發機制View事件
- View的事件分發機制分析View事件
- View事件分發機制分析View事件
- Flutter——原生View的Touch事件分發流程FlutterView事件
- Android ViewGroup 事件分發機制詳解AndroidView事件
- Android View 的事件體系 -- 事件分發機制AndroidView事件
- 【Android原始碼】View的事件分發機制Android原始碼View事件
- 10分鐘理解 Android View 事件分發機制AndroidView事件
- Android事件分發:從原始碼角度分析View事件分發機制Android事件原始碼View
- 《Android開發藝術探索》——View事件分發機制AndroidView事件
- Android 事件分發機制原始碼解析-view層Android事件原始碼View
- 2018.03.08、View的事件分發機制筆記View事件筆記
- View 事件傳遞體系知識梳理(1) 事件分發機制View事件
- Android自定義View之事件分發機制總結AndroidView事件
- 基於原始碼分析 Android View 事件分發機制原始碼AndroidView事件
- Android從原始碼角度剖析View事件分發機制Android原始碼View事件
- 《Android藝術開發探索》學習筆記之View的事件體系(View的事件分發機制)Android筆記View事件
- Android Touch事件傳遞機制全面解析(從WMS到View樹)Android事件View
- View事件機制分析View事件
- 學習總結 -- View 事件分發機制和滑動衝突View事件
- Android事件分發機制Android事件
- 這可能是最"俗"的View的事件分發機制(含Demo講解)View事件
- Android的MotionEvent事件分發機制Android事件
- Android 事件分發機制的理解Android事件
- android View的事件分發AndroidView事件
- Android的Touch事件處理機制介紹Android事件
- Android Touch事件分發過程Android事件
- Android事件分發機制三:事件分發工作流程Android事件
- 事件分發機制(一):解惑篇事件
- cocos EventDispatcher事件分發機制事件
- TouchEvent事件分發機制全解析事件
- Android事件分發機制探究Android事件
- Android事件分發機制解析Android事件
- 事件分發之View事件處理事件View