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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

View工作原理(一)事件传递原理详解

發(fā)布時間:2025/6/15 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 View工作原理(一)事件传递原理详解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

目錄(?)[+]

轉載請說明出處:http://blog.csdn.net/ff20081528/article/details/17353869
一、準備知識

1、視圖坐標與布局坐標的區(qū)別如下圖所示:

上圖是一個坐標系,這個坐標系是無邊無際的。這個無邊無際的坐標系即視圖坐標。手機屏幕可視范圍內的坐標即手機屏幕的布局坐標(坐標原點是屏幕的左上方的(0,0)位置)即A點。屏幕里面的子視圖里面可視范圍內的坐標即子視圖的布局坐標(坐標原點是子視圖的左上方的(0,0)位置)即B點。 2、android中布局關系 ?
二、例子說明事件分發(fā)過程
這里我寫了一個布局文件,展示效果如上圖。當我點擊View1,事件的分發(fā)過程是這樣的: 1、ViewGroup3的dispatchTouchEvent()方法會被調用。 2、ViewGroup3調用ViewGroup2的dispatchTouchEvent()方法。 3、ViewGroup2調用ViewGroup1的dispatchTouchEvent()方法。 4、ViewGroup1會調用View1的dispatchTouchEvent()方法。 5、View1的dispatchTouchEvent()方法調用自己的onTouchEvent()方法。在onTouchEvent方法中處理點擊事件。處理完了后會返回一個true給調用它的dispatchTouchEvent()方法。 6、ViewGroup1的dispatchTouchEvent()方法會返回一個true值給ViewGroup2的dispatchTouchEvent()方法。這樣一直將則個true值返回到ViewGroup3的dispatchTouchEvent()方法。ViewGroup3在將這個值返回給調用它的方法。這樣一個事件分發(fā)過程結束。 轉載請說明出處:http://blog.csdn.net/ff20081528/article/details/17353869 ? 三、ViewGroup中處理消息的詳細過程 通過上面的列子對事件分發(fā)的過程有個大概的了解之后,我們通過ViewGroup中的dispatchTouchEvent()方法源碼和View中的dispatchTouchEvent()方法及touchEvent方法源碼來詳細了解android是怎樣處理這個過程的。 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.??
  • ????????????????????????}??
  • ????????????????????}??
  • ????????????????}??
  • ????????????}??
  • ????????}??
  • ??
  • ????????boolean?isUpOrCancel?=?(action?==?MotionEvent.ACTION_UP)?||??
  • ????????????????(action?==?MotionEvent.ACTION_CANCEL);??
  • ??
  • ????????if?(isUpOrCancel)?{??
  • ????????????//?Note,?we've?already?copied?the?previous?state?to?our?local??
  • ????????????//?variable,?so?this?takes?effect?on?the?next?event??
  • ????????????mGroupFlags?&=?~FLAG_DISALLOW_INTERCEPT;??
  • ????????}??
  • ??
  • ????????//?The?event?wasn't?an?ACTION_DOWN,?dispatch?it?to?our?target?if??
  • ????????//?we?have?one.??
  • ????????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);??
  • ????????}??
  • ??
  • ????????//?if?have?a?target,?see?if?we're?allowed?to?and?want?to?intercept?its??
  • ????????//?events??
  • ????????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;??
  • ????????}??
  • ??
  • ????????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);??
  • ??
  • ????????if?((target.mPrivateFlags?&?CANCEL_NEXT_UP_EVENT)?!=?0)?{??
  • ????????????ev.setAction(MotionEvent.ACTION_CANCEL);??
  • ????????????target.mPrivateFlags?&=?~CANCEL_NEXT_UP_EVENT;??
  • ????????????mMotionTarget?=?null;??
  • ????????}??
  • ??
  • ????????return?target.dispatchTouchEvent(ev);??
  • ????}??
  • ?

    代碼說明:

    1、(代碼2-4行)處理窗口處于模糊顯示狀態(tài)下的消息。所謂的模糊顯示是指,應用程序可以設置當前窗口為模糊狀態(tài),此時窗口內部的所有視圖將顯示為模糊效果。這樣的目的是為了隱藏窗口中的內容,對于其中的各個視圖而言,可以設置改視圖的FILTER_TOUCHERS_WHEN_OBSCURED標識,如存在該標識,則意味著用戶希望不要處理該消息。
    2、(代碼6-11行)將ViewGroup的布局坐標轉換成視圖坐標。
    3、(代碼16-58行)處理ACTION_DOWN消息,其作用是判斷該視圖坐標落到了哪個子視圖中。首先判斷該ViewGroup本身是否被禁止獲取TOUCH消息,如果沒有禁止,并且回調函數(shù)onInterceptTouchEvent中沒有消耗該消息,則開始尋找子視圖。調用child.getHitRect(frame)方法獲取該子視圖在父視圖中的布局坐標,即ViewGroup將child放在什么位置,這個位置相對于該child來講是布局坐標,而對于該ViewGroup來講卻是視圖坐標,參數(shù)frame是執(zhí)行完畢后的位置輸出矩形。得到位置后,就可以調用frame.contain()方法判斷該消息位置是否被包含到了該child中,如果包含,并且該child也是一個ViewGroup,則準備遞歸調用該child的dispatchTouchEvent(),在調用之前,首先需要把坐標重新轉換到child的坐標系中。接下來判斷該child是否是ViewGroup類。如果是,則詆毀調用ViewGroupdispatchTouchEvent(),重新從第一步開始執(zhí)行;如果child不是ViewGroup,而是一個View,則意味著詆毀調用的結束。

    4、(代碼61-68行)如果是ACTION_UP或者是ACTION_CANCEL消息,則清除mGroupFlags中的FLAG_DISALLOW_INTERCEPT標識,即允許該ViewGroup截獲消息。也就是說,常見的情況就是當用戶釋放手指,下一次按下時,該ViewGroup本身可以重新截獲消息,而在按下還沒有釋放期間,ViewGroup本身是不允許截獲消息的。

    5、(代碼70-82)判斷target變量是否為空。空代表了所有子窗口都沒有消耗該消息,所以該ViewGroup本事需要處理該消息。然后還原消息的原始位置,將視圖坐標重新轉換成布局坐標,接著調用super.dispatchTouchEvent(ev),即View類的中的dispatchTouchEvent()方法(該方法會判斷是否進行調用touchEvent()方法來處理,到后面的View類的源碼中再介紹)。

    6、(代碼84-121)處理target存在,并且變量disallowInterceptfalse,即允許截獲,在默認情況下ViewGroup都是允許截獲消息的,只有當該ViewGroup的子視圖調用父視圖的requestDisallowdInterceptTouchEvent()方法時,方可禁止父視圖再次截獲消息,但每次ACTION_UP消息或者ACTION_CANCEL消息之后,該ViewGroup又會重新截獲消息。ViewGroup本身不允許截獲消息或者允許截獲但是卻沒有消耗消息,于是調用target.dispatchTouchEvent(ev)方法把該消息繼續(xù)交給目標視圖處理,在調用該方法前需要檢查target中是否申明過要取消隨后的消息,即mPrivateFlags中包含 CANCEL_NEXT_UP_EVENT,如果是,則把消息action值修改為ACTION_CANCEL,將mMotionTarget變?yōu)榭?#xff0c;因為target不想處理接下來的消息了,那么就可以認為沒有target了。

    ?

    四、View中處理消息的詳細過程

    dispatchTouchEvent()方法的源碼

    [java] view plaincopy
  • /**?
  • ????*?Pass?the?touch?screen?motion?event?down?to?the?target?view,?or?this?
  • ????*?view?if?it?is?the?target.?
  • ????*?
  • ????*?@param?event?The?motion?event?to?be?dispatched.?
  • ????*?@return?True?if?the?event?was?handled?by?the?view,?false?otherwise.?
  • ????*/??
  • ???public?boolean?dispatchTouchEvent(MotionEvent?event)?{??
  • ???????if?(!onFilterTouchEventForSecurity(event))?{??
  • ???????????return?false;??
  • ???????}??
  • ??
  • ???????if?(mOnTouchListener?!=?null?&&?(mViewFlags?&?ENABLED_MASK)?==?ENABLED?&&??
  • ???????????????mOnTouchListener.onTouch(this,?event))?{??
  • ???????????return?true;??
  • ???????}??
  • ???????return?onTouchEvent(event);??
  • ???}??
  • 處理窗口處于模糊顯示狀態(tài)下的消息。然后回調視圖監(jiān)聽著的onTouch()方法,如果監(jiān)聽者消耗了該消息,則直接返回。如果沒有則調用ViewonTouchEvent()方法。

    ?

    onTouchEvent()方法源碼

    [java] view plaincopy
  • ?/**?
  • ?????*?Implement?this?method?to?handle?touch?screen?motion?events.?
  • ?????*?
  • ?????*?@param?event?The?motion?event.?
  • ?????*?@return?True?if?the?event?was?handled,?false?otherwise.?
  • ?????*/??
  • ????public?boolean?onTouchEvent(MotionEvent?event)?{??
  • ????????final?int?viewFlags?=?mViewFlags;??
  • ??
  • ????????if?((viewFlags?&?ENABLED_MASK)?==?DISABLED)?{??
  • ????????????//?A?disabled?view?that?is?clickable?still?consumes?the?touch??
  • ????????????//?events,?it?just?doesn't?respond?to?them.??
  • ????????????return?(((viewFlags?&?CLICKABLE)?==?CLICKABLE?||??
  • ????????????????????(viewFlags?&?LONG_CLICKABLE)?==?LONG_CLICKABLE));??
  • ????????}??
  • ??
  • ????????if?(mTouchDelegate?!=?null)?{??
  • ????????????if?(mTouchDelegate.onTouchEvent(event))?{??
  • ????????????????return?true;??
  • ????????????}??
  • ????????}??
  • ??
  • ????????if?(((viewFlags?&?CLICKABLE)?==?CLICKABLE?||??
  • ????????????????(viewFlags?&?LONG_CLICKABLE)?==?LONG_CLICKABLE))?{??
  • ????????????switch?(event.getAction())?{??
  • ????????????????case?MotionEvent.ACTION_UP:??
  • ????????????????????boolean?prepressed?=?(mPrivateFlags?&?PREPRESSED)?!=?0;??
  • ????????????????????if?((mPrivateFlags?&?PRESSED)?!=?0?||?prepressed)?{??
  • ????????????????????????//?take?focus?if?we?don't?have?it?already?and?we?should?in??
  • ????????????????????????//?touch?mode.??
  • ????????????????????????boolean?focusTaken?=?false;??
  • ????????????????????????if?(isFocusable()?&&?isFocusableInTouchMode()?&&?!isFocused())?{??
  • ????????????????????????????focusTaken?=?requestFocus();??
  • ????????????????????????}??
  • ??
  • ????????????????????????if?(!mHasPerformedLongPress)?{??
  • ????????????????????????????//?This?is?a?tap,?so?remove?the?longpress?check??
  • ????????????????????????????removeLongPressCallback();??
  • ??
  • ????????????????????????????//?Only?perform?take?click?actions?if?we?were?in?the?pressed?state??
  • ????????????????????????????if?(!focusTaken)?{??
  • ????????????????????????????????//?Use?a?Runnable?and?post?this?rather?than?calling??
  • ????????????????????????????????//?performClick?directly.?This?lets?other?visual?state??
  • ????????????????????????????????//?of?the?view?update?before?click?actions?start.??
  • ????????????????????????????????if?(mPerformClick?==?null)?{??
  • ????????????????????????????????????mPerformClick?=?new?PerformClick();??
  • ????????????????????????????????}??
  • ????????????????????????????????if?(!post(mPerformClick))?{??
  • ????????????????????????????????????performClick();??
  • ????????????????????????????????}??
  • ????????????????????????????}??
  • ????????????????????????}??
  • ??
  • ????????????????????????if?(mUnsetPressedState?==?null)?{??
  • ????????????????????????????mUnsetPressedState?=?new?UnsetPressedState();??
  • ????????????????????????}??
  • ??
  • ????????????????????????if?(prepressed)?{??
  • ????????????????????????????mPrivateFlags?|=?PRESSED;??
  • ????????????????????????????refreshDrawableState();??
  • ????????????????????????????postDelayed(mUnsetPressedState,??
  • ????????????????????????????????????ViewConfiguration.getPressedStateDuration());??
  • ????????????????????????}?else?if?(!post(mUnsetPressedState))?{??
  • ????????????????????????????//?If?the?post?failed,?unpress?right?now??
  • ????????????????????????????mUnsetPressedState.run();??
  • ????????????????????????}??
  • ????????????????????????removeTapCallback();??
  • ????????????????????}??
  • ????????????????????break;??
  • ??
  • ????????????????case?MotionEvent.ACTION_DOWN:??
  • ????????????????????if?(mPendingCheckForTap?==?null)?{??
  • ????????????????????????mPendingCheckForTap?=?new?CheckForTap();??
  • ????????????????????}??
  • ????????????????????mPrivateFlags?|=?PREPRESSED;??
  • ????????????????????mHasPerformedLongPress?=?false;??
  • ????????????????????postDelayed(mPendingCheckForTap,?ViewConfiguration.getTapTimeout());??
  • ????????????????????break;??
  • ??
  • ????????????????case?MotionEvent.ACTION_CANCEL:??
  • ????????????????????mPrivateFlags?&=?~PRESSED;??
  • ????????????????????refreshDrawableState();??
  • ????????????????????removeTapCallback();??
  • ????????????????????break;??
  • ??
  • ????????????????case?MotionEvent.ACTION_MOVE:??
  • ????????????????????final?int?x?=?(int)?event.getX();??
  • ????????????????????final?int?y?=?(int)?event.getY();??
  • ??
  • ????????????????????//?Be?lenient?about?moving?outside?of?buttons??
  • ????????????????????int?slop?=?mTouchSlop;??
  • ????????????????????if?((x?<?0?-?slop)?||?(x?>=?getWidth()?+?slop)?||??
  • ????????????????????????????(y?<?0?-?slop)?||?(y?>=?getHeight()?+?slop))?{??
  • ????????????????????????//?Outside?button??
  • ????????????????????????removeTapCallback();??
  • ????????????????????????if?((mPrivateFlags?&?PRESSED)?!=?0)?{??
  • ????????????????????????????//?Remove?any?future?long?press/tap?checks??
  • ????????????????????????????removeLongPressCallback();??
  • ??
  • ????????????????????????????//?Need?to?switch?from?pressed?to?not?pressed??
  • ????????????????????????????mPrivateFlags?&=?~PRESSED;??
  • ????????????????????????????refreshDrawableState();??
  • ????????????????????????}??
  • ????????????????????}??
  • ????????????????????break;??
  • ????????????}??
  • ????????????return?true;??
  • ????????}??
  • ??
  • ????????return?false;??
  • ????}??
  • ??
  • <p>???</p>??

  • 1、代碼10-15)處理該視圖是否為disable狀態(tài),如果是,什么都不處理,返回true,即消耗該消息。

    2、(代碼17-21)消息代理處理消息。所謂的消息代理是指,可以給某個View指定一個消息處理代理,當View收到消息時,首先將該消息派發(fā)給其代理進行處理。如果代理內部消耗了該消息,則View不需要在進行任何處理;如果代理沒有處理,則view繼續(xù)處理。在這里不用多管,不會影響事件處理的邏輯和結果。

    3、(代碼22-102)判斷該視圖是否可以點擊,如果不可以點擊,則直接返回false,即不處理該消息。否則,真正開始執(zhí)行觸摸消息的默認處理邏輯,該邏輯分別處理了ACTION_DOWNACTION_MOVEACTION_UP消息.

    (26-70)處理ACTION_UP消息,判斷該UP消息是否發(fā)生在前面所講的哪一個監(jiān)測時間段中,并據此進行不同的處理。

    (71-78)在ACTION_DOWN消息中,給mPrivateFlags變量添加PRESSED標識,并將變量mHasPerformLongPress設置為false,然后啟動tap監(jiān)測,即發(fā)送一個異步延遲消息。

    對于觸摸消息而言,消息本身沒有repeat的屬性,一次觸摸只有一個ACTION_DOWN消息,按下來就是連續(xù)的ACTION_MOVE消息,并最終以處理ACTION_CANCEL消息.

    (80-85)ACTION_CANCLE消息處理,這里只需清除PRESSED標識,刷新視圖狀態(tài),然后再關閉tap監(jiān)測即可。

    (86-105)對ACTION_MOVE消息進行處理。具體邏輯包括,判斷是否移動到了視圖區(qū)域以外,如果是,則刪除tap或者longPress的監(jiān)測,并清除mPrivateFlags中的PRESSED標識,然后調用refreshDrawableState()刷新視圖狀態(tài),這將導致對背景狀態(tài)進行重繪。

    ?

    ?五、例子程序

    通過代碼可能完全理解事件的分發(fā)過程有點難,下面通過一個例子程序來鞏固下事件分發(fā)的過程。

    例子程序的UI如下:

    布局如下:

    [java] view plaincopy
  • <org.sunday.main.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"??
  • ????android:orientation="vertical"?>??
  • ??????
  • ?????<org.sunday.main.MyLinearLayout??
  • ????????android:id="@+id/ll2"??
  • ????????android:layout_width="match_parent"??
  • ????????android:layout_height="100dp"??
  • ????????android:background="@drawable/ll_selector"??
  • ????????android:orientation="vertical"?>??
  • ????</org.sunday.main.MyLinearLayout>??
  • ??
  • ????<org.sunday.main.MyLinearLayout??
  • ????????android:id="@+id/ll1"??
  • ????????android:layout_width="match_parent"??
  • ????????android:layout_marginTop="20dp"??
  • ????????android:layout_height="100dp"??
  • ????????android:background="@drawable/ll_selector"??
  • ????????android:orientation="vertical"?>??
  • ??
  • ????????<org.sunday.main.MyLinearLayout??
  • ????????????android:layout_width="80dp"??
  • ????????????android:layout_height="50dp"??
  • ????????????android:layout_marginTop="20dp"??
  • ????????????android:clickable="true"??
  • ????????????android:background="@drawable/ll_selector2"??
  • ????????????android:orientation="vertical"?>??
  • ????????</org.sunday.main.MyLinearLayout>??
  • ????</org.sunday.main.MyLinearLayout>??
  • ??
  • ????<org.sunday.main.MyLinearLayout??
  • ????????android:id="@+id/ll3"??
  • ????????android:layout_width="match_parent"??
  • ????????android:layout_height="100dp"??
  • ????????android:layout_marginTop="20dp"??
  • ????????android:background="@drawable/ll_selector"??
  • ????????android:orientation="vertical"?>??
  • ??
  • ????????<org.sunday.main.MyButton??
  • ????????????android:layout_width="wrap_content"??
  • ????????????android:layout_height="60dp"??
  • ????????????android:layout_margin="20dp"??
  • ????????????android:background="@drawable/btn_selector"??
  • ????????????android:text="button1"?/>??
  • ????</org.sunday.main.MyLinearLayout>??
  • ??
  • ????<org.sunday.main.MyLinearLayout??
  • ????????android:id="@+id/ll4"??
  • ????????android:layout_width="match_parent"??
  • ????????android:layout_height="100dp"??
  • ????????android:layout_marginTop="20dp"??
  • ????????android:background="@drawable/ll_selector"??
  • ????????android:orientation="vertical"?>??
  • ??
  • ????????<org.sunday.main.MyButtonWithOutEvent??
  • ????????????android:layout_width="wrap_content"??
  • ????????????android:layout_height="60dp"??
  • ????????????android:layout_margin="20dp"??
  • ????????????android:background="@drawable/btn_selector"??
  • ????????????android:text="button2"?/>??
  • ????</org.sunday.main.MyLinearLayout>??
  • ??
  • </org.sunday.main.MyLinearLayout>??

  • MyLinearLayout.java

    [java] view plaincopy
  • package?org.sunday.main;??
  • ??
  • 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?final?static?String?TAG?=?"MyLinearLayout";??
  • ??
  • ????public?MyLinearLayout(Context?context)?{??
  • ????????super(context);??
  • ????}??
  • ??
  • ????public?MyLinearLayout(Context?context,?AttributeSet?attrs)?{??
  • ????????super(context,?attrs);??
  • ????}??
  • ??????
  • ????@Override??
  • ????public?boolean?dispatchTouchEvent(MotionEvent?ev)?{??
  • ????????Log.e(TAG,?"dispatchTouchEvent()----------------"?+?this.toString());??
  • ????????boolean?isTrue?=?super.dispatchTouchEvent(ev);??
  • ????????Log.e(TAG,?"dispatchTouchEvent()??isTrue?=?"?+?isTrue?+?"?---------------?;"+?this.toString());??
  • ????????return?isTrue;??
  • ????}??
  • ??????
  • ????@Override??
  • ????public?boolean?onTouchEvent(MotionEvent?event)?{??
  • ????????Log.e(TAG,?"onTouchEvent()----------------"?+?this.toString());??
  • ????????boolean?isTrue?=?super.onTouchEvent(event);??
  • ????????Log.e(TAG,?"onTouchEvent()??isTrue?=?"?+?isTrue+?"-----------------??;"+?this.toString());??
  • ????????return?isTrue;??
  • ????}??
  • ??????
  • }??

  • MyButton.java

    [java] view plaincopy
  • package?org.sunday.main;??
  • ??
  • import?android.content.Context;??
  • import?android.util.AttributeSet;??
  • import?android.util.Log;??
  • import?android.view.MotionEvent;??
  • import?android.widget.Button;??
  • ??
  • public?class?MyButton?extends?Button?{??
  • ????private?final?static?String?TAG?=?"MyButton";??
  • ??
  • ????public?MyButton(Context?context)?{??
  • ????????super(context);??
  • ????}??
  • ??
  • ????public?MyButton(Context?context,?AttributeSet?attrs)?{??
  • ????????super(context,?attrs);??
  • ????}??
  • ??
  • ????@Override??
  • ????public?boolean?dispatchTouchEvent(MotionEvent?event)?{??
  • ????????Log.e(TAG,?"dispatchTouchEvent()----------------");??
  • ????????boolean?isTrue?=?super.dispatchTouchEvent(event);??
  • ????????Log.e(TAG,?"dispatchTouchEvent??isTrue?=?"?+?isTrue);??
  • ????????return?isTrue;??
  • ????}??
  • ??????
  • ????@Override??
  • ????public?boolean?onTouchEvent(MotionEvent?event)?{??
  • ????????Log.e(TAG,?"onTouchEvent()----------------");??
  • ????????boolean?isTrue?=?super.onTouchEvent(event);??
  • ????????Log.e(TAG,?"onTouchEvent??isTrue?=?"?+?isTrue);??
  • ????????return?isTrue;??
  • ????}??
  • }??

  • MyButtonWithOutEvent.java

    [java] view plaincopy
  • package?org.sunday.main;??
  • ??
  • import?android.content.Context;??
  • import?android.util.AttributeSet;??
  • import?android.util.Log;??
  • import?android.view.MotionEvent;??
  • import?android.widget.Button;??
  • ??
  • public?class?MyButtonWithOutEvent?extends?Button?{??
  • ????private?final?static?String?TAG?=?"MyButtonWithOutEvent";??
  • ??
  • ????public?MyButtonWithOutEvent(Context?context)?{??
  • ????????super(context);??
  • ????}??
  • ??
  • ????public?MyButtonWithOutEvent(Context?context,?AttributeSet?attrs)?{??
  • ????????super(context,?attrs);??
  • ????}??
  • ??
  • ????@Override??
  • ????public?boolean?dispatchTouchEvent(MotionEvent?event)?{??
  • ????????Log.e(TAG,?"dispatchTouchEvent()----------------"+?this.toString());??
  • //??????boolean?isTrue?=?super.dispatchTouchEvent(event);??
  • //??????Log.e(TAG,?"isTrue?=?"?+?isTrue);??
  • ????????return?false;??
  • ????}??
  • ??????
  • ????@Override??
  • ????public?boolean?onTouchEvent(MotionEvent?event)?{??
  • ????????Log.e(TAG,?"onTouchEvent()----------------");??
  • ????????boolean?isTrue?=?super.onTouchEvent(event);??
  • ????????Log.e(TAG,?"onTouchEvent??isTrue?=?"?+?isTrue);??
  • ????????return?isTrue;??
  • ????}??
  • }??

  • ?點擊例子一,后臺打印的日志如下:

    ?

    解釋:例子一的布局中只有兩個ViewGroup子類對象,當點擊例子一區(qū)域,根ViewGroup首先分發(fā)touch事件,因為它有child,所以接著會將事件傳遞到它的孩子ViewGroup。孩子ViewGroup發(fā)現(xiàn)自己沒有child了,所以它就得自己處理這個touch事件。所以會調用OnTouchEvent()方法來處理這個事件。處理完之后會返回一個true,一直返回給根ViewGroup。

    ?

    點擊例子二的綠色區(qū)域,后臺打印日志如下:

    解釋:例子二和例子一差不多,只不過多了一個ViewGroup而已。

    ?

    點擊例子三得黃色區(qū)域,后臺打印日志如下:

    ?解釋:例子三相比于例子二只是將最上層的ViewGroup換成了View,原理一樣。

    ?

    點擊例子四的黃色區(qū)域,打印日志如下:

    解釋:在這個程序中,對于MyLinearLayout和MyButton的dispachTouchEvent()和onTouchEvent()發(fā)放的邏輯并沒有進行任何的修改。而對于MyButtonWithOutEvent,在dispatchTouchEvent()方法中,直接返回的false(即不進行事件的任何處理),那么事件傳遞到這里時,它將會把事件返回給調用它的父ViewGroup進行處理,所以這里我們看到的是MyLinearLayout調用了onTouchEvent()。

    ?

    點擊例子三得button和點擊例子四的button效果圖如下:

    ?例子三中是button響應了這個touch事件,而在例子四中則是LinearLayout響應了這個touch事件。

    demo:點擊打開鏈接

    總結

    以上是生活随笔為你收集整理的View工作原理(一)事件传递原理详解的全部內容,希望文章能夠幫你解決所遇到的問題。

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