ViewGroup/View的事件分發機制(1)(Touch,down,move,up)
true:攔截;false:不攔截.
自定義ViewGroup實現各種滑動效果的,不可避免的會出現很多事件的衝突,對ViewGroup事件分發機制的瞭解,也有益於大家瞭解衝突產生的原因,以及對衝突進行處理~
View體系的繪製流程是從ViewRootImpl的performTraversals方法開始的;
View的測量大小流程:performMeasure –> measure –> onMeasure等方法;
View的測量位置流程:performLayout –> layout –> onLayout等方法;
View的繪製流程:performDraw-> draw-> onDraw等方法;
自定義控制元件集合庫- https://github.com/HpWens/MeiWidgetView
-- View 的測量、佈局、繪製三大流程都是交由 ViewRootImpl 發起,而且還都是在 performTraversals() 方法中發起的,所以這個方法的邏輯很複雜,因為每次都需要根據相應狀態判斷是否需要三個流程都走,有時可能只需要執行 performDraw() 繪製流程,有時可能只執行 performMeasure() 測量和 performLayout() 佈局流程(一般測量和佈局流程是一起執行的)。不管哪個流程都會遍歷一次 View 樹,所以其實介面的繪製是需要遍歷很多次的,如果頁面層次太過複雜,每一幀需要重新整理的 View 又很多時,耗時就會長一點。
1.dispatchTouchEvent()事件分發,當Touch事件發生時,dispatchTouchEvent()方法會以隧道方式(即從根元素依次向內層元素傳遞)將事件向下傳遞。一般來說我們不會去改寫這個方法
return true :事件交由當前view進行消費,同時事件停止向下傳遞
return false:事件交由上層view或者Activity進行消費
return super.dispatchTouchEvent():系統預設的事件分發處理邏輯
2.onInerceptTouchEvent()事件攔截,該方法只有ViewGroup擁有。
return true:表示攔截事件,把攔截的事件交由當前的view處理
return fasle:表示不攔截事件,事件會被傳遞到子view的dispatchTouchEvent()來進行事件分發onTouchEvent()事件響應
3.onTouchEvent()方法會以冒泡方式(即從最內層的子元素依次向外傳遞)將事件向上傳遞
return true:表示消費了事件,事件停止向上傳遞
return false:表示沒有處理事件,事件繼續向上傳遞
return super.onTouchEvent():預設處理事件的邏輯,和返回false差不多
-- Android事件分發機制詳解- https://blog.csdn.net/feelinghappy/article/details/54378797
事件在哪些物件之間進行傳遞?一個點選事件產生後,傳遞順序是:Activity(Window) -> ViewGroup -> View。
事件傳遞情況:
從Activity A—->ViewGroup B—>View C,從上往下呼叫dispatchTouchEvent()
再由View C—>ViewGroup B —>Activity A,從下往上呼叫onTouchEvent()
- Android6.0 ViewGroup/View 事件分發機制詳解-http://www.2cto.com/kf/201606/514943.html
mDecor是何許人也,其實就是PhoneWindow中的一個內部類DecorView的例項物件,是Activity的Window視窗中最根部的父容器,我們平時在Activity的onCreate()方法中,通過setContentView()給設定的佈局容器,都屬於mDecor的子View mContentView物件的子view,而DecorView又繼承於FrameLayout,FrameLayout又繼承於ViewGroup。
Activity.dispatchTouchEvent是來自Window.Callback.dispatchTouchEvent,Activity.dispatchTouchEvent呼叫的位置是在PhoneWindow.DecorView.
dispatchTouchEvent,此處指的是DecorView它本身重寫的那個,而不是super的,注意兩者的區別.
Android中activity觸控操作dispatchTouchEvent
觸控事件先進行此操作;
float downX = 0, downY = 0;
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = ev.getX();
downY = ev.getY();
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
break;
}
return super.dispatchTouchEvent(ev);
}
dispatchTouchEvent是處理觸控事件分發,事件(多數情況)是從Activity的dispatchTouchEvent開始的。執行super.dispatchTouchEvent(ev),事件向下分發。
onInterceptTouchEvent是ViewGroup提供的方法,預設返回false,返回true表示攔截。
onTouchEvent是View中提供的方法,ViewGroup也有這個方法,view中不提供onInterceptTouchEvent。view中預設返回true,表示消費了這個事件。
android中的Touch事件都是從ACTION_DOWN開始的:
單手指操作:ACTION_DOWN---ACTION_MOVE----ACTION_UP
多手指操作:ACTION_DOWN---ACTION_POINTER_DOWN---ACTION_MOVE--ACTION_POINTER_UP---ACTION_UP.
-- Android介面渲染流程線:
UI物件—->CPU處理為多維圖形,紋理 —–通過OpenGL ES介面呼叫GPU—-> GPU對圖進行光柵化(Frame Rate ) —->硬體時鐘(Refresh Rate)—-垂直同步—->投射到螢幕。
-- 在 Android M 版本開始,GPU Profiling 工具把渲染操作拆解成如下8個詳細的步驟進行顯示:
1.swap Buffers;
2.Command Issue;
3.Sync & Upload
4.Draw
5.Measure/Layout
6.Animation
7.Input Handling
8.Misc Time/Vsync Delay
-- Activity是如何將事件分發到相應的View、ViewGroup當中去的:
Activity.dispatchTouchEvent(MotionEvent event) -> PhoneWindow.superDispatchTouchEvent(MotionEvent event) -> DecorView.superDispatchTouchEvent(MotionEvent event) -> FrameLayout.dispatchTouchEvent(MotionEvent event) -> ViewGroup.dispatchTouchEvent(MotionEvent event) -> 再逐級分發到各個ViewGroup/View當中去.
> Activity、ViewGroup與View的Touch事件:
ViewGroupA.dispatchTouchEvent ->
ViewGroupA.onInterceptTouchEvent(return false, 沒有進行攔截) ->
ViewGroupB.dispatchTouchEvent ->
ViewGroupB.onInterceptTouchEvent(return false, 沒有進行攔截) ->
ViewC.dispatchTouchEvent ->ViewC.onTouchEvent(return false, 沒有消費) ->
ViewC.dispatchTouchEvent(return false, 將onTouchEvent的處理結果回傳給ViewGroupB) ->
ViewGroupB.onTouchEvent(return false, 也沒有消費) ->
ViewB.dispatchTouchEvent(return false, 將onTouchEvent的處理結果回傳給ViewGroupA) ->
ViewGroupA.onTouchEvent(return false, 也沒有消費) ->
ViewA.dispatchTouchEvent(return false, 最終將onTouchEvent的處理結果回傳給Activity) ->
Activity對事件進行最終處理。
要不要捕獲事件--攔截事件--分發事件--處理事件??
> 自定義ViewGroup及ViewGroup的事件分發
-- Android ViewGroup事件分發機制- http://blog.csdn.net/lmj623565791/article/details/39102591
1.定義控制元件
public class CustomLinearLayout extends LinearLayout {
private static final String TAG = CustomLinearLayout.class.getSimpleName();
public CustomLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
//分發事件
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int action = ev.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(ev);
}
//點選、觸控事件處理
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
Log.e(TAG, "onTouchEvent ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e(TAG, "onTouchEvent ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e(TAG, "onTouchEvent ACTION_UP");
break;
default:
break;
}
return super.onTouchEvent(event);
}
//攔截觸控事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
Log.e(TAG, "onInterceptTouchEvent ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e(TAG, "onInterceptTouchEvent ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e(TAG, "onInterceptTouchEvent ACTION_UP");
break;
default:
break;
}
return super.onInterceptTouchEvent(ev);
}
@Override
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
Log.e(TAG, "requestDisallowInterceptTouchEvent ");
super.requestDisallowInterceptTouchEvent(disallowIntercept);
}
}
2.XML佈局:
<?xml version="1.0" encoding="utf-8"?>
<com.desaco.practiceknowing.view_event_dispatch.CustomLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.desaco.practiceknowing.view_event_dispatch.CustomButton
android:id="@+id/id_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp"
android:text="click me" />
</com.desaco.practiceknowing.view_event_dispatch.CustomLinearLayout>
3.MOVE一下,不然不會觸發MOVE事件,看一下日誌的輸出:
09-06 09:57:27.287: E/MyLinearLayout(959): dispatchTouchEvent ACTION_DOWN
09-06 09:57:27.287: E/MyLinearLayout(959): onInterceptTouchEvent ACTION_DOWN
09-06 09:57:27.287: E/MyButton(959): dispatchTouchEvent ACTION_DOWN
09-06 09:57:27.297: E/MyButton(959): onTouchEvent ACTION_DOWN
09-06 09:57:27.297: E/MyButton(959): onTouchEvent ACTION_MOVE
09-06 09:57:27.327: E/MyLinearLayout(959): dispatchTouchEvent ACTION_MOVE
09-06 09:57:27.327: E/MyLinearLayout(959): onInterceptTouchEvent ACTION_MOVE
09-06 09:57:27.337: E/MyButton(959): dispatchTouchEvent ACTION_MOVE
09-06 09:57:27.337: E/MyButton(959): onTouchEvent ACTION_MOVE
09-06 09:57:27.457: E/MyLinearLayout(959): dispatchTouchEvent ACTION_UP
09-06 09:57:27.457: E/MyLinearLayout(959): onInterceptTouchEvent ACTION_UP
09-06 09:57:27.457: E/MyButton(959): dispatchTouchEvent ACTION_UP
09-06 09:57:27.457: E/MyButton(959): onTouchEvent ACTION_UP
可以看到大體的事件流程為:
MyLinearLayout的dispatchTouchEvent -> MyLinearLayout的onInterceptTouchEvent -> MyButton的dispatchTouchEvent ->Mybutton的onTouchEvent ,最先捕獲到事件的為View所在的ViewGroup..
可以看出,在View上觸發事件,最先捕獲到事件的為View所在的ViewGroup,然後才會到View自身~
> 下面我們按照日誌的輸出,進入原始碼,原始碼分析
ViewGroup - dispatchTouchEvent
1、ViewGroup - dispatchTouchEvent - ACTION_DOWN
首先是ViewGroup的dispatchTouchEvent方法:
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (!onFilterTouchEventForSecurity(ev)) {
return false;
}
final int action = ev.getAction();
final float xf = ev.getX();
final float yf = ev.getY();
final float scrolledXFloat = xf + mScrollX;
final float scrolledYFloat = yf + mScrollY;
final Rect frame = mTempRect;
boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (action == MotionEvent.ACTION_DOWN) {
if (mMotionTarget != null) {
// this is weird, we got a pen down, but we thought it was
// already down!
// XXX: We should probably send an ACTION_UP to the current
// target.
mMotionTarget = null;
}
// If we're disallowing intercept or if we're allowing and we didn't
// intercept
if (disallowIntercept || !onInterceptTouchEvent(ev)) {
// reset this event's action (just to protect ourselves)
ev.setAction(MotionEvent.ACTION_DOWN);
// We know we want to dispatch the event down, find a child
// who can handle it, start with the front-most child.
final int scrolledXInt = (int) scrolledXFloat;
final int scrolledYInt = (int) scrolledYFloat;
final View[] children = mChildren;
final int count = mChildrenCount;
for (int i = count - 1; i >= 0; i--) {
final View child = children[i];
if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
|| child.getAnimation() != null) {
child.getHitRect(frame);
if (frame.contains(scrolledXInt, scrolledYInt)) {
// offset the event to the view's coordinate system
final float xc = scrolledXFloat - child.mLeft;
final float yc = scrolledYFloat - child.mTop;
ev.setLocation(xc, yc);
child.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
if (child.dispatchTouchEvent(ev)) {
// Event handled, we have a target now.
mMotionTarget = child;
return true;
}
// The event didn't get handled, try the next view.
// Don't reset the event's location, it's not
// necessary here.
}
}
}
}
} ....//other code omitted
程式碼比較長,決定分段貼出,首先貼出的是ACTION_DOWN事件相關的程式碼。
16行:進入ACTION_DOWN的處理
17-23行:將mMotionTarget置為null
26行:進行判斷:if(disallowIntercept || !onInterceptTouchEvent(ev))
兩種可能會進入if程式碼段
1、當前不允許攔截,即disallowIntercept =true,
2、當前允許攔截但是不攔截,即disallowIntercept =false,但是onInterceptTouchEvent(ev)返回false ;
注:disallowIntercept 可以通過viewGroup.requestDisallowInterceptTouchEvent(boolean);進行設定,後面會詳細說;而onInterceptTouchEvent(ev)可以進行復寫。
36-57行:開始遍歷所有的子View
41行:進行判斷當前的x,y座標是否落在子View身上,如果在,47行,執行child.dispatchTouchEvent(ev),就進入了View的dispatchTouchEvent程式碼中了,如果不瞭解請參考:Android View的事件分發機制,當child.dispatchTouchEvent(ev)返回true,則為mMotionTarget=child;然後return true;
ViewGroup的ACTION_DOWN分析結束,總結一下:
ViewGroup實現捕獲到DOWN事件,如果程式碼中不做TOUCH事件攔截,則開始查詢當前x,y是否在某個子View的區域內,如果在,則把事件分發下去
按照日誌,接下來到達ACTION_MOVE
2、ViewGroup - dispatchTouchEvent - ACTION_MOVE
首先我們原始碼進行刪減,只留下MOVE相關的程式碼:
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
final float xf = ev.getX();
final float yf = ev.getY();
final float scrolledXFloat = xf + mScrollX;
final float scrolledYFloat = yf + mScrollY;
final Rect frame = mTempRect;
boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
//...ACTION_DOWN
//...ACTIN_UP or ACTION_CANCEL
// The event wasn't an ACTION_DOWN, dispatch it to our target if
// we have one.
final View target = mMotionTarget;
// if have a target, see if we're allowed to and want to intercept its
// events
if (!disallowIntercept && onInterceptTouchEvent(ev)) {
//....
}
// finally offset the event to the target's coordinate system and
// dispatch the event.
final float xc = scrolledXFloat - (float) target.mLeft;
final float yc = scrolledYFloat - (float) target.mTop;
ev.setLocation(xc, yc);
return target.dispatchTouchEvent(ev);
}
18行:把ACTION_DOWN時賦值的mMotionTarget,付給target ;
23行:if (!disallowIntercept && onInterceptTouchEvent(ev)) 當前允許攔截且攔截了,才進入IF體,當然了預設是不會攔截的~這裡執行了onInterceptTouchEvent(ev)
28-30行:把座標系統轉化為子View的座標系統
32行:直接return target.dispatchTouchEvent(ev);
可以看到,正常流程下,ACTION_MOVE在檢測完是否攔截以後,直接呼叫了子View.dispatchTouchEvent,事件分發下去;
最後就是ACTION_UP了
3、ViewGroup - dispatchTouchEvent - ACTION_UP
public boolean dispatchTouchEvent(MotionEvent ev) {
if (!onFilterTouchEventForSecurity(ev)) {
return false;
}
final int action = ev.getAction();
final float xf = ev.getX();
final float yf = ev.getY();
final float scrolledXFloat = xf + mScrollX;
final float scrolledYFloat = yf + mScrollY;
final Rect frame = mTempRect;
boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (action == MotionEvent.ACTION_DOWN) {...}
boolean isUpOrCancel = (action == MotionEvent.ACTION_UP) ||
(action == MotionEvent.ACTION_CANCEL);
if (isUpOrCancel) {
mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
}
final View target = mMotionTarget;
if(target ==null ){...}
if (!disallowIntercept && onInterceptTouchEvent(ev)) {...}
if (isUpOrCancel) {
mMotionTarget = null;
}
// finally offset the event to the target's coordinate system and
// dispatch the event.
final float xc = scrolledXFloat - (float) target.mLeft;
final float yc = scrolledYFloat - (float) target.mTop;
ev.setLocation(xc, yc);
return target.dispatchTouchEvent(ev);
}
17行:判斷當前是否是ACTION_UP
21,28行:分別重置攔截標誌位以及將DOWN賦值的mMotionTarget置為null,都UP了,當然置為null,下一次DOWN還會再賦值的~
最後,修改座標系統,然後呼叫target.dispatchTouchEvent(ev);
正常情況下,即我們上例整個程式碼的流程我們已經走完了:
1、ACTION_DOWN中,ViewGroup捕獲到事件,然後判斷是否攔截,如果沒有攔截,則找到包含當前x,y座標的子View,賦值給mMotionTarget,然後呼叫mMotionTarget.dispatchTouchEvent
2、ACTION_MOVE中,ViewGroup捕獲到事件,然後判斷是否攔截,如果沒有攔截,則直接呼叫mMotionTarget.dispatchTouchEvent(ev)
3、ACTION_UP中,ViewGroup捕獲到事件,然後判斷是否攔截,如果沒有攔截,則直接呼叫mMotionTarget.dispatchTouchEvent(ev)
當然了在分發之前都會修改下座標系統,把當前的x,y分別減去child.left 和 child.top ,然後傳給child;
3、關於攔截
1、如何攔截
上面的總結都是基於:如果沒有攔截;那麼如何攔截呢?
複寫ViewGroup的onInterceptTouchEvent方法:
@Override
public boolean onInterceptTouchEvent(MotionEvent ev)
{
int action = ev.getAction();
switch (action)
{
case MotionEvent.ACTION_DOWN:
//如果你覺得需要攔截
return true ;
case MotionEvent.ACTION_MOVE:
//如果你覺得需要攔截
return true ;
case MotionEvent.ACTION_UP:
//如果你覺得需要攔截
return true ;
}
return false;
}
預設是不攔截的,即返回false;如果你需要攔截,只要return true就行了,這要該事件就不會往子View傳遞了,並且如果你在DOWN retrun true ,則DOWN,MOVE,UP子View都不會捕獲事件;如果你在MOVE return true , 則子View在MOVE和UP都不會捕獲事件。
原因很簡單,當onInterceptTouchEvent(ev) return true的時候,會把mMotionTarget 置為null ;
2、如何不被攔截
如果ViewGroup的onInterceptTouchEvent(ev) 當ACTION_MOVE時return true ,即攔截了子View的MOVE以及UP事件;
此時子View希望依然能夠響應MOVE和UP時該咋辦呢?
Android給我們提供了一個方法:requestDisallowInterceptTouchEvent(boolean) 用於設定是否允許攔截,我們在子View的dispatchTouchEvent中直接這麼寫:
@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);
}
getParent().requestDisallowInterceptTouchEvent(true); 這樣即使ViewGroup在MOVE的時候return true,子View依然可以捕獲到MOVE以及UP事件。
從原始碼也可以解釋:
ViewGroup MOVE和UP攔截的原始碼是這樣的:
if (!disallowIntercept && onInterceptTouchEvent(ev)) {
final float xc = scrolledXFloat - (float) target.mLeft;
final float yc = scrolledYFloat - (float) target.mTop;
mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
ev.setAction(MotionEvent.ACTION_CANCEL);
ev.setLocation(xc, yc);
if (!target.dispatchTouchEvent(ev)) {
// target didn't handle ACTION_CANCEL. not much we can do
// but they should have.
}
// clear the target
mMotionTarget = null;
// Don't dispatch this event to our own view, because we already
// saw it when intercepting; we just want to give the following
// event to the normal onTouchEvent().
return true;
}
當我們把disallowIntercept設定為true時,!disallowIntercept直接為false,於是攔截的方法體就被跳過了~
注:如果ViewGroup在onInterceptTouchEvent(ev) ACTION_DOWN裡面直接return true了,那麼子View是木有辦法的捕獲事件的~~~
4、如果沒有找到合適的子View
我們的例項,直接點選ViewGroup內的按鈕,當然直接很順利的走完整個流程;
但是有兩種特殊情況
1、ACTION_DOWN的時候,子View.dispatchTouchEvent(ev)返回的為false ;
如果你仔細看了,你會注意到ViewGroup的dispatchTouchEvent(ev)的ACTION_DOWN程式碼是這樣的
if (child.dispatchTouchEvent(ev)) {
// Event handled, we have a target now.
mMotionTarget = child;
return true;
}
只有在child.dispatchTouchEvent(ev)返回true了,才會認為找到了能夠處理當前事件的View,即mMotionTarget = child;
但是如果返回false,那麼mMotionTarget 依然是null
mMotionTarget 為null會咋樣呢?
其實ViewGroup也是View的子類,如果沒有找到能夠處理該事件的子View,或者乾脆就沒有子View;
那麼,它作為一個View,就相當於View的事件轉發了~~直接super.dispatchTouchEvent(ev);
原始碼是這樣的:
final View target = mMotionTarget;
if (target == null) {
// We don't have a target, this means we're handling the
// event as a regular view.
ev.setLocation(xf, yf);
if ((mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) {
ev.setAction(MotionEvent.ACTION_CANCEL);
mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
}
return super.dispatchTouchEvent(ev);
}
我們沒有一個能夠處理該事件的目標元素,意味著我們需要自己處理~~~就相當於傳統的View~
2、那麼什麼時候子View.dispatchTouchEvent(ev)返回的為true
如果你仔細看了上篇部落格,你會發現只要子View支援點選或者長按事件一定返回true~~
原始碼是這樣的:
if (((viewFlags & CLICKABLE) == CLICKABLE ||
(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
return true ; }
5、總結
關於程式碼流程上面已經總結過了~
1、如果ViewGroup找到了能夠處理該事件的View,則直接交給子View處理,自己的onTouchEvent不會被觸發;
2、可以通過複寫onInterceptTouchEvent(ev)方法,攔截子View的事件(即return true),把事件交給自己處理,則會執行自己對應的 onTouchEvent方法
3、子View可以通過呼叫getParent().requestDisallowInterceptTouchEvent(true); 阻止ViewGroup對其MOVE或者UP事件進行攔 截;
> 好了,那麼實際應用中能解決哪些問題呢?
比如你需要寫一個類似slidingmenu的左側隱藏menu,主Activity上有個Button、ListView或者任何可以響應點選的View,你在當前View上死命的滑動,選單欄也出不來;因為MOVE事件被子View處理了~ 你需要這麼做:在ViewGroup的dispatchTouchEvent中判斷使用者是不是想顯示選單,如果是,則在onInterceptTouchEvent(ev)攔截子View的事件;自己進行處理,這樣自己的onTouchEvent就可以順利展現出選單欄了~~
相關文章
- ViewGroup/View的事件分發機制(2)(Touch,down,move,up)View事件
- ViewGroup/View的事件分發機制(3)(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事件
- View 事件傳遞體系知識梳理(1) 事件分發機制View事件
- 【Android原始碼】View的事件分發機制Android原始碼View事件
- 10分鐘理解 Android View 事件分發機制AndroidView事件
- Android事件分發:從原始碼角度分析View事件分發機制Android事件原始碼View
- 《Android開發藝術探索》——View事件分發機制AndroidView事件
- Android 事件分發機制原始碼解析-view層Android事件原始碼View
- 2018.03.08、View的事件分發機制筆記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