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

歡迎訪問 生活随笔!

生活随笔

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

Android

Android之事件分发机制

發(fā)布時間:2024/7/23 Android 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android之事件分发机制 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

本文主要包括以下內容

  • view的事件分發(fā)
  • viewGroup的事件分發(fā)
  • 首先來看兩張圖

    在執(zhí)行touch事件時

  • 首先執(zhí)行dispatchTouchEvent方法,執(zhí)行事件分發(fā)。

  • 再執(zhí)行onInterceptTouchEvent方法,判斷是否中斷事件,返回true時中斷,執(zhí)行自己的onTouchEvnet方法.

  • 最后執(zhí)行onTouchEvent方法,處理事件

  • View的事件分發(fā)

    不管是DOWN,MOVE,UP都會按照下面的順序執(zhí)行:
    1、dispatchTouchEvent
    2、 setOnTouchListener的onTouch
    3、onTouchEvent

    其中

    如果我們設置了setOnTouchListener,并且return true,那么View自己的onTouchEvent就不會被執(zhí)行了

    總結

    1、整個View的事件轉發(fā)流程是:
    View.dispatchEvent->View.setOnTouchListener->View.onTouchEvent

    在dispatchTouchEvent中會進行OnTouchListener的判斷,如果OnTouchListener不為null且返回true,則表示事件被消費,onTouchEvent不會被執(zhí)行;否則執(zhí)行onTouchEvent。

    2、onTouchEvent中的DOWN,MOVE,UP

    • DOWN時:
      a、首先設置標志為PREPRESSED,設置mHasPerformedLongPress=false ;然后發(fā)出一個115ms后的mPendingCheckForTap;
      b、如果115ms內沒有觸發(fā)UP,則將標志置為PRESSED,清除PREPRESSED標志,同時發(fā)出一個延時為500-115ms的,檢測長按任務消息;
      c、如果500ms內(從DOWN觸發(fā)開始算),則會觸發(fā)LongClickListener:

    此時如果LongClickListener不為null,則會執(zhí)行回調,同時如果LongClickListener.onClick返回true,才把mHasPerformedLongPress設置為true;否則mHasPerformedLongPress依然為false;

    • MOVE時:
      主要就是檢測用戶是否劃出控件,如果劃出了:
      115ms內,直接移除mPendingCheckForTap;
      115ms后,則將標志中的PRESSED去除,同時移除長按的檢查:removeLongPressCallback();

    • UP時:
      a、如果115ms內,觸發(fā)UP,此時標志為PREPRESSED,則執(zhí)行UnsetPressedState,setPressed(false);會把setPress轉發(fā)下去,可以在View中復寫dispatchSetPressed方法接收;
      b、如果是115ms-500ms間,即長按還未發(fā)生,則首先移除長按檢測,執(zhí)行onClick回調;
      c、如果是500ms以后,那么有兩種情況:
      i.設置了onLongClickListener,且onLongClickListener.onClick返回true,則點擊事件OnClick事件無法觸發(fā);
      ii.沒有設置onLongClickListener或者onLongClickListener.onClick返回false,則點擊事件OnClick事件依然可以觸發(fā);
      d、最后執(zhí)行mUnsetPressedState.run(),將setPressed傳遞下去,然后將PRESSED標識去除;

    最后問個問題,然后再運行個例子結束:
    1、setOnLongClickListener和setOnClickListener是否只能執(zhí)行一個
    不是的,只要setOnLongClickListener中的onClick返回false,則兩個都會執(zhí)行;返回true則會屏幕setOnClickListener

    Android ViewGroup事件分發(fā)機制

    大體的事件流程為:
    MyLinearLayout的dispatchTouchEvent -> MyLinearLayout的onInterceptTouchEvent -> MyButton的dispatchTouchEvent ->Mybutton的onTouchEvent

    可以看出,在View上觸發(fā)事件,最先捕獲到事件的為View所在的ViewGroup,然后才會到View自身~

    1、ACTION_DOWN中,ViewGroup捕獲到事件,然后判斷是否攔截,如果沒有攔截,則找到包含當前x,y坐標的子View,賦值給mMotionTarget,然后調用 mMotionTarget.dispatchTouchEvent

    2、ACTION_MOVE中,ViewGroup捕獲到事件,然后判斷是否攔截,如果沒有攔截,則直接調用mMotionTarget.dispatchTouchEvent(ev)

    3、ACTION_UP中,ViewGroup捕獲到事件,然后判斷是否攔截,如果沒有攔截,則直接調用mMotionTarget.dispatchTouchEvent(ev)
    當然了在分發(fā)之前都會修改下坐標系統(tǒng),把當前的x,y分別減去child.left 和 child.top ,然后傳給child;

    關于攔截

    如何攔截

    復寫ViewGroup的onInterceptTouchEvent方法:

    @Overridepublic 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 ;

    如何不被攔截

    如果ViewGroup的onInterceptTouchEvent(ev) 當ACTION_MOVE時return true ,即攔截了子View的MOVE以及UP事件;
    此時子View希望依然能夠響應MOVE和UP時該咋辦呢?
    Android給我們提供了一個方法: requestDisallowInterceptTouchEvent(boolean) 用于設置是否允許攔截,我們在子View的dispatchTouchEvent中直接這么寫:

    @Overridepublic 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在onInterceptTouchEvent(ev) ACTION_DOWN里面直接return true了,那么子View是木有辦法的捕獲事件的~~~

    如果沒有找到合適的子View

    1、ACTION_DOWN的時候,子View.dispatchTouchEvent(ev)返回的為false ;

    則不處理,向上傳遞,由父view處理

    總結

    關于代碼流程上面已經(jīng)總結過了~
    1、如果ViewGroup找到了能夠處理該事件的View,則直接交給子View處理,自己的onTouchEvent不會被觸發(fā);
    2、可以通過復寫onInterceptTouchEvent(ev)方法,攔截子View的事件(即return true),把事件交給自己處理,則會執(zhí)行自己對應的onTouchEvent方法
    3、子View可以通過調用 getParent().requestDisallowInterceptTouchEvent(true); 阻止ViewGroup對其MOVE或者UP事件進行攔截;

    好了,那么實際應用中能解決哪些問題呢?
    比如你需要寫一個類似slidingmenu的左側隱藏menu,主Activity上有個Button、ListView或者任何可以響應點擊的View,你在當前View上死命的滑動,菜單欄也出不來;因為MOVE事件被子View處理了~ 你需要這么做:在ViewGroup的dispatchTouchEvent中判斷用戶是不是想顯示菜單,如果是,則在onInterceptTouchEvent(ev)攔截子View的事件;自己進行處理,這樣自己的onTouchEvent就可以順利展現(xiàn)出菜單欄了~

    參考鏈接

    Android View 事件分發(fā)機制 源碼解析 (上) - Hongyang - 博客頻道 - CSDN.NET

    Android ViewGroup事件分發(fā)機制 - Hongyang - 博客頻道 - CSDN.NET

    總結

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

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