日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android ViewGroup事件分发机制

發布時間:2025/6/15 Android 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android ViewGroup事件分发机制 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
理~

1、案例

首先我們接著上一篇的代碼,在代碼中添加一個自定義的LinearLayout:

[java] view plaincopy
  • package?com.example.zhy_event03;??
  • ??
  • import?android.content.Context;??
  • import?android.util.AttributeSet;??
  • import?android.util.Log;??
  • import?android.view.MotionEvent;??
  • import?android.widget.LinearLayout;??
  • ??
  • public?class?MyLinearLayout?extends?LinearLayout??
  • {??
  • ????private?static?final?String?TAG?=?MyLinearLayout.class.getSimpleName();??
  • ??
  • ????public?MyLinearLayout(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);??
  • ????}??
  • ??
  • }??

  • 繼承LinearLayout,然后復寫了與事件分發機制有關的代碼,添加上了日志的打印~

    然后看我們的布局文件:

    [html] view plaincopy
  • <com.example.zhy_event03.MyLinearLayout?xmlns:android="http://schemas.android.com/apk/res/android"??
  • ????xmlns:tools="http://schemas.android.com/tools"??
  • ????android:layout_width="match_parent"??
  • ????android:layout_height="match_parent"??
  • ????tools:context=".MainActivity"?>??
  • ??
  • ????<com.example.zhy_event03.MyButton??
  • ????????android:id="@+id/id_btn"??
  • ????????android:layout_width="wrap_content"??
  • ????????android:layout_height="wrap_content"??
  • ????????android:text="click?me"?/>??
  • ??
  • </com.example.zhy_event03.MyLinearLayout>??

  • MyLinearLayout中包含一個MyButton,MyButton都上篇博客中已經出現過,這里就不再貼代碼了,不清楚可以去查看~

    然后MainActivity就是直接加載布局,沒有任何代碼~~~

    直接運行我們的代碼,然后點擊我們的Button,依然是有意的MOVE一下,不然不會觸發MOVE事件,看一下日志的輸出:

    [html] view plaincopy
  • 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上觸發事件,最先捕獲到事件的為View所在的ViewGroup,然后才會到View自身~

    下面我們按照日志的輸出,進入源碼~

    2、源碼分析

    ViewGroup -?dispatchTouchEvent

    1、ViewGroup -?dispatchTouchEvent - ACTION_DOWN

    首先是ViewGroup的dispatchTouchEvent方法:

    [java] view plaincopy
  • @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相關的代碼:

    [java] view plaincopy
  • @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

    [java] view plaincopy
  • 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方法:

    [java] view plaincopy
  • @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中直接這么寫:

    [java] view plaincopy
  • @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攔截的源碼是這樣的:

    [java] view plaincopy
  • 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代碼是這樣的

    [java] view plaincopy
  • 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);

    源碼是這樣的:

    [java] view plaincopy
  • 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~~

    源碼是這樣的:

    [java] view plaincopy
  • ???
  • 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就可以順利展現出菜單欄了~~

    總結

    以上是生活随笔為你收集整理的Android ViewGroup事件分发机制的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。