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

歡迎訪問 生活随笔!

生活随笔

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

Android

Android的Touch系统简介(一)

發布時間:2023/12/19 Android 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android的Touch系统简介(一) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、Android?touch事件的相關概念

用戶的Touch事件被包裝成MotionEvent

用戶當前的touch事件主要類型有:

?

ACTION_DOWN: 表示用戶開始觸摸.

?ACTION_MOVE: 表示用戶在移動(手指或者其他)

?ACTION_UP:表示用戶抬起了手指?

ACTION_CANCEL:表示手勢被取消了,一些關于這個事件類型的討論見:http://stackoverflow.com/questions/11960861/what-causes-a-motionevent-action-cancel-in-android?

ACTION_OUTSIDE: 表示用戶觸碰超出了正常的UI邊界.

ACTION_POINTER_DOWN:有一個非主要的手指按下了.

ACTION_POINTER_UP:一個非主要的手指抬起來了

touch事件的元數據包括:

?

touch的位置

手指的個數

touch事件的時間

一個touch手勢被定義為以ACTION_DOWN開始和以?ACTION_UP結束。

?

二、Touch事件的處理流程

當用戶觸摸屏幕時,觸發Activity調用dispatchTouchEvent

事件對象會按自頂向下的順序在View Tree中傳遞

?

? ? ?父View(ViewGroups)會調用dispatchTouchEvent將Event傳遞給子View ? ?

? ? Event在任何時候都可能被攔截

事件流會順著View鏈遞歸向下傳遞直到被消耗

?

若某個View想處理touch事件,必須先消耗ACTION_DOWN。考慮到效率,后續的事件將不會向下傳遞。

若某個事件未被消耗,最后會被Activity的onTouchEvent()消耗

若任何View或ViewGroup設置了OnTouchListener,touch事件將被攔截。

?

Activity.dispathcTouchEvent()的源碼分析:

?

[java]?view plaincopy
  • /**?
  • ????*?Called?to?process?touch?screen?events.?You?can?override?this?to?
  • ????*?intercept?all?touch?screen?events?before?they?are?dispatched?to?the?
  • ????*?window.?Be?sure?to?call?this?implementation?for?touch?screen?events?
  • ????*?that?should?be?handled?normally.?
  • ????*?
  • ????*?@param?ev?The?touch?screen?event.?
  • ????*?
  • ????*?@return?boolean?Return?true?if?this?event?was?consumed.?
  • ????*/??
  • ???public?boolean?dispatchTouchEvent(MotionEvent?ev)?{??
  • ???????if?(ev.getAction()?==?MotionEvent.ACTION_DOWN)?{??
  • ???????????onUserInteraction();??
  • ???????}??
  • ???????if?(getWindow().superDispatchTouchEvent(ev))?{??
  • ???????????return?true;??
  • ???????}??
  • ???????return?onTouchEvent(ev);??
  • ???}??

  • 由代碼可以看出,對于應用層,該函數在touch事件發生后首先被調用。onUserInteraction()是一個空函數,可被用戶重載以進行相關處理。Event隨后將被傳遞到關聯到root view的window。若子view消耗了該Event,則返回true,否則Event最后被Activity的onTouchEvent()消耗。

    ?

    ViewGroup.dispatchTouchEvent()的源碼分析如下:

    ?

    [java]?view plaincopy
  • public?boolean?dispatchTouchEvent(MotionEvent?ev)?{??
  • ????????if?(mInputEventConsistencyVerifier?!=?null)?{??
  • ????????????mInputEventConsistencyVerifier.onTouchEvent(ev,?1);??
  • ????????}??
  • ????????boolean?handled?=?false;??
  • ????????if?(onFilterTouchEventForSecurity(ev))?{??
  • ????????????final?int?action?=?ev.getAction();??
  • ????????????final?int?actionMasked?=?action?&?MotionEvent.ACTION_MASK;??
  • ????????????//?處理初始的down事件??
  • ????????????if?(actionMasked?==?MotionEvent.ACTION_DOWN)?{??
  • ????????????????//當新開始一個touch事件時,拋棄先前的touch狀態??
  • ????????????????//當app切換,發生ANR或一些其他的touch狀態發生時,framework會丟棄或取消先前的touch狀態??
  • ????????????????cancelAndClearTouchTargets(ev);??
  • ????????????????resetTouchState();??
  • ????????????}??
  • ????????????//?檢查是否進行事件攔截??
  • ????????????final?boolean?intercepted;??
  • ????????????if?(actionMasked?==?MotionEvent.ACTION_DOWN??
  • ????????????????????||?mFirstTouchTarget?!=?null)?{??
  • ????????????????final?boolean?disallowIntercept?=?(mGroupFlags?&?FLAG_DISALLOW_INTERCEPT)?!=?0;??
  • ????????????????if?(!disallowIntercept)?{??
  • ????????????????????//回調onInterceptTouchEvent(),返回false表示不攔截touch,否則攔截touch事件。??
  • ????????????????????intercepted?=?onInterceptTouchEvent(ev);??
  • ????????????????????ev.setAction(action);?//?restore?action?in?case?it?was?changed??
  • ????????????????}?else?{??
  • ????????????????????intercepted?=?false;??
  • ????????????????}??
  • ????????????}?else?{??
  • ????????????????//沒有touch事件的傳遞對象,同時touch動作不是初始動作down,所以ViewGroup繼續攔截事件??
  • ????????????????intercepted?=?true;??
  • ????????????}??
  • ????????????//?檢查cancel事件??
  • ????????????final?boolean?canceled?=?resetCancelNextUpFlag(this)??
  • ????????????????????||?actionMasked?==?MotionEvent.ACTION_CANCEL;??
  • ????????????//?如果有第二個手指touch,更新touch目標列表。touch目標列表是一個View數組??
  • ????????????final?boolean?split?=?(mGroupFlags?&?FLAG_SPLIT_MOTION_EVENTS)?!=?0;??
  • ????????????TouchTarget?newTouchTarget?=?null;??
  • ????????????boolean?alreadyDispatchedToNewTouchTarget?=?false;??
  • ????????????if?(!canceled?&&?!intercepted)?{??
  • ????????????????if?(actionMasked?==?MotionEvent.ACTION_DOWN??
  • ????????????????????????||?(split?&&?actionMasked?==?MotionEvent.ACTION_POINTER_DOWN)??
  • ????????????????????????||?actionMasked?==?MotionEvent.ACTION_HOVER_MOVE)?{??
  • ????????????????????final?int?actionIndex?=?ev.getActionIndex();?//?always?0?for?down??
  • ????????????????????final?int?idBitsToAssign?=?split???1?<<?ev.getPointerId(actionIndex)??
  • ????????????????????????????:?TouchTarget.ALL_POINTER_IDS;??
  • ????????????????????//?Clean?up?earlier?touch?targets?for?this?pointer?id?in?case?they??
  • ????????????????????//?have?become?out?of?sync.??
  • ????????????????????removePointersFromTouchTargets(idBitsToAssign);??
  • ????????????????????final?int?childrenCount?=?mChildrenCount;??
  • ????????????????????if?(newTouchTarget?==?null?&&?childrenCount?!=?0)?{??
  • ????????????????????????final?float?x?=?ev.getX(actionIndex);??
  • ????????????????????????final?float?y?=?ev.getY(actionIndex);??
  • ????????????????????????//?找到一個能接受Event的子View,再對子View的View樹進行遍歷??
  • ????????????????????????final?View[]?children?=?mChildren;??
  • ????????????????????????final?boolean?customOrder?=?isChildrenDrawingOrderEnabled();??
  • ????????????????????????//判斷每個子View是否是TouchTarget,若是則添加到TouchTarget鏈表中??
  • ????????????????????????for?(int?i?=?childrenCount?-?1;?i?>=?0;?i--)?{??
  • ????????????????????????????final?int?childIndex?=?customOrder????
  • ????????????????????????????????????getChildDrawingOrder(childrenCount,?i)?:?i;??
  • ????????????????????????????final?View?child?=?children[childIndex];??
  • ????????????????????????????if?(!canViewReceivePointerEvents(child)??
  • ????????????????????????????????????||?!isTransformedTouchPointInView(x,?y,?child,?null))?{??
  • ????????????????????????????????continue;??
  • ????????????????????????????}??
  • ????????????????????????????newTouchTarget?=?getTouchTarget(child);??
  • ????????????????????????????if?(newTouchTarget?!=?null)?{??
  • ????????????????????????????????//?若子View處于touch目標中,同時已經接收了touch事件,則為器增加新的touch點??
  • ????????????????????????????????newTouchTarget.pointerIdBits?|=?idBitsToAssign;??
  • ????????????????????????????????break;??
  • ????????????????????????????}??
  • ????????????????????????????resetCancelNextUpFlag(child);??
  • ????????????????????????????//把MotionEvent的點坐標轉換到子View的坐標系中,為ViewGroup創建一個新TouchTarget,TouchTarget包含了子View??
  • ????????????????????????????if?(dispatchTransformedTouchEvent(ev,?false,?child,?idBitsToAssign))?{??
  • ????????????????????????????????//?Child?wants?to?receive?touch?within?its?bounds.??
  • ????????????????????????????????mLastTouchDownTime?=?ev.getDownTime();??
  • ????????????????????????????????mLastTouchDownIndex?=?childIndex;??
  • ????????????????????????????????mLastTouchDownX?=?ev.getX();??
  • ????????????????????????????????mLastTouchDownY?=?ev.getY();??
  • ????????????????????????????????newTouchTarget?=?addTouchTarget(child,?idBitsToAssign);??
  • ????????????????????????????????alreadyDispatchedToNewTouchTarget?=?true;??
  • ????????????????????????????????break;??
  • ????????????????????????????}??
  • ????????????????????????}??
  • ????????????????????}??
  • ????????????????????if?(newTouchTarget?==?null?&&?mFirstTouchTarget?!=?null)?{??
  • ????????????????????????//?沒有發現接收event的子View,把Touch點賦給最早添加到TouchTarget鏈中的對象??
  • ????????????????????????newTouchTarget?=?mFirstTouchTarget;??
  • ????????????????????????while?(newTouchTarget.next?!=?null)?{??
  • ????????????????????????????newTouchTarget?=?newTouchTarget.next;??
  • ????????????????????????}??
  • ????????????????????????newTouchTarget.pointerIdBits?|=?idBitsToAssign;??
  • ????????????????????}??
  • ????????????????}??
  • ????????????}??
  • ????????????//?傳遞給touch目標??
  • ????????????if?(mFirstTouchTarget?==?null)?{??
  • ????????????????//?若沒有Touch目標,則把自己當成一個View,調用??
  • ????????????????handled?=?dispatchTransformedTouchEvent(ev,?canceled,?null,??
  • ????????????????????????TouchTarget.ALL_POINTER_IDS);??
  • ????????????}?else?{??
  • ????????????????//?Dispatch?to?touch?targets,?excluding?the?new?touch?target?if?we?already??
  • ????????????????//?dispatched?to?it.?Cancel?touch?targets?if?necessary.??
  • ????????????????TouchTarget?predecessor?=?null;??
  • ????????????????TouchTarget?target?=?mFirstTouchTarget;??
  • ????????????????while?(target?!=?null)?{??
  • ????????????????????final?TouchTarget?next?=?target.next;??
  • ????????????????????//若已被處理,則忽略。??
  • ????????????????????if?(alreadyDispatchedToNewTouchTarget?&&?target?==?newTouchTarget)?{??
  • ????????????????????????handled?=?true;??
  • ????????????????????}?else?{??
  • ????????????????????????final?boolean?cancelChild?=?resetCancelNextUpFlag(target.child)??
  • ????????????????????????????????||?intercepted;??
  • ????????????????????????//傳遞給子View處理??
  • ????????????????????????if?(dispatchTransformedTouchEvent(ev,?cancelChild,??
  • ????????????????????????????????target.child,?target.pointerIdBits))?{??
  • ????????????????????????????handled?=?true;??
  • ????????????????????????}??
  • ????????????????????????if?(cancelChild)?{??
  • ????????????????????????????if?(predecessor?==?null)?{??
  • ????????????????????????????????mFirstTouchTarget?=?next;??
  • ????????????????????????????}?else?{??
  • ????????????????????????????????predecessor.next?=?next;??
  • ????????????????????????????}??
  • ????????????????????????????target.recycle();??
  • ????????????????????????????target?=?next;??
  • ????????????????????????????continue;??
  • ????????????????????????}??
  • ????????????????????}??
  • ????????????????????predecessor?=?target;??
  • ????????????????????target?=?next;??
  • ????????????????}??
  • ????????????}??
  • ????????????//?若在觸摸點發生了up或cancel,則更新TouchTarget鏈表??
  • ????????????if?(canceled??
  • ????????????????????||?actionMasked?==?MotionEvent.ACTION_UP??
  • ????????????????????||?actionMasked?==?MotionEvent.ACTION_HOVER_MOVE)?{??
  • ????????????????resetTouchState();??
  • ????????????}?else?if?(split?&&?actionMasked?==?MotionEvent.ACTION_POINTER_UP)?{??
  • ????????????????final?int?actionIndex?=?ev.getActionIndex();??
  • ????????????????final?int?idBitsToRemove?=?1?<<?ev.getPointerId(actionIndex);??
  • ????????????????removePointersFromTouchTargets(idBitsToRemove);??
  • ????????????}??
  • ????????}??
  • ????????if?(!handled?&&?mInputEventConsistencyVerifier?!=?null)?{??
  • ????????????mInputEventConsistencyVerifier.onUnhandledEvent(ev,?1);??
  • ????????}??
  • ????????return?handled;??
  • ????}??

  • ViewGroup中將TouchEvent傳遞給子View的函數為dispatchTransformedTouchEvent(),源代碼如下:

    ?

    ?

    [java]?view plaincopy
  • /**?
  • ????*?Transforms?a?motion?event?into?the?coordinate?space?of?a?particular?child?view,?
  • ????*?filters?out?irrelevant?pointer?ids,?and?overrides?its?action?if?necessary.?
  • ????*?If?child?is?null,?assumes?the?MotionEvent?will?be?sent?to?this?ViewGroup?instead.?
  • ????*/??
  • ???private?boolean?dispatchTransformedTouchEvent(MotionEvent?event,?boolean?cancel,??
  • ???????????View?child,?int?desiredPointerIdBits)?{??
  • ???????final?boolean?handled;??
  • ???????//?Canceling?motions?is?a?special?case.?We?don't?need?to?perform?any?transformations??
  • ???????//?or?filtering.?The?important?part?is?the?action,?not?the?contents.??
  • ???????//?cancel動作是個特列,無需坐標轉換或過濾。??
  • ???????final?int?oldAction?=?event.getAction();??
  • ???????if?(cancel?||?oldAction?==?MotionEvent.ACTION_CANCEL)?{??
  • ???????????event.setAction(MotionEvent.ACTION_CANCEL);??
  • ???????????if?(child?==?null)?{??
  • ???????????????handled?=?super.dispatchTouchEvent(event);??
  • ???????????}?else?{??
  • ???????????????handled?=?child.dispatchTouchEvent(event);??
  • ???????????}??
  • ???????????event.setAction(oldAction);??
  • ???????????return?handled;??
  • ???????}??
  • ???????//?計算將被傳遞的點的數量。??
  • ???????final?int?oldPointerIdBits?=?event.getPointerIdBits();??
  • ???????final?int?newPointerIdBits?=?oldPointerIdBits?&?desiredPointerIdBits;??
  • ??
  • ???????//?Motion事件沒有對應點,則丟棄這個Motion??
  • ???????if?(newPointerIdBits?==?0)?{??
  • ???????????return?false;??
  • ???????}??
  • ??
  • ???????/*若點的數量一致則無需進行不相關的點坐標轉換,調用子View的dispatchTouchEvent*/??
  • ???????//?If?the?number?of?pointers?is?the?same?and?we?don't?need?to?perform?any?fancy??
  • ???????//?irreversible?transformations,?then?we?can?reuse?the?motion?event?for?this??
  • ???????//?dispatch?as?long?as?we?are?careful?to?revert?any?changes?we?make.??
  • ???????//?Otherwise?we?need?to?make?a?copy.??
  • ???????/*該變量用于保存坐標轉換后的MoetionEvent*/??
  • ???????final?MotionEvent?transformedEvent;??
  • ???????if?(newPointerIdBits?==?oldPointerIdBits)?{??
  • ???????????if?(child?==?null?||?child.hasIdentityMatrix())?{??
  • ???????????????if?(child?==?null)?{??
  • ???????????????????handled?=?super.dispatchTouchEvent(event);??
  • ???????????????}?else?{??
  • ???????????????????final?float?offsetX?=?mScrollX?-?child.mLeft;??
  • ???????????????????final?float?offsetY?=?mScrollY?-?child.mTop;??????
  • ???????????????????/*直接對MotionEvent進行坐標變換,將MotionEvent傳遞下去*/??
  • ???????????????????event.offsetLocation(offsetX,?offsetY);??
  • ???????????????????handled?=?child.dispatchTouchEvent(event);??
  • ???????????????????/*回復MotionEvent*/??
  • ???????????????????event.offsetLocation(-offsetX,?-offsetY);??
  • ???????????????}??
  • ???????????????return?handled;??
  • ???????????}??
  • ???????????transformedEvent?=?MotionEvent.obtain(event);??
  • ???????}?else?{??
  • ???????????transformedEvent?=?event.split(newPointerIdBits);??
  • ???????}??
  • ???????//?Perform?any?necessary?transformations?and?dispatch.??
  • ???????if?(child?==?null)?{??????
  • ???????????/*調用父類即View的dispatchTouchEvent方法,該方法會調用onTouchEvent*/??
  • ???????????handled?=?super.dispatchTouchEvent(transformedEvent);??
  • ???????}?else?{??
  • ???????????final?float?offsetX?=?mScrollX?-?child.mLeft;??
  • ???????????final?float?offsetY?=?mScrollY?-?child.mTop;??
  • ???????????transformedEvent.offsetLocation(offsetX,?offsetY);??
  • ???????????if?(!?child.hasIdentityMatrix())?{??
  • ???????????????transformedEvent.transform(child.getInverseMatrix());??
  • ???????????}??
  • ???????????/*傳遞給子View處理*/??
  • ???????????handled?=?child.dispatchTouchEvent(transformedEvent);??
  • ???????}??
  • ???????//?Done.??
  • ???????transformedEvent.recycle();??
  • ???????return?handled;??
  • ???}??
  • 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?(mInputEventConsistencyVerifier?!=?null)?{??
  • ??????????mInputEventConsistencyVerifier.onTouchEvent(event,?0);??
  • ??????}??
  • ??????if?(onFilterTouchEventForSecurity(event))?{??
  • ??????????//noinspection?SimplifiableIfStatement??
  • ??????????ListenerInfo?li?=?mListenerInfo;??
  • ??????????/*先調用listener接口*/??
  • ??????????if?(li?!=?null?&&?li.mOnTouchListener?!=?null?&&?(mViewFlags?&?ENABLED_MASK)?==?ENABLED??
  • ??????????????????&&?li.mOnTouchListener.onTouch(this,?event))?{??
  • ??????????????return?true;??
  • ??????????}??
  • ?????????/*若MotionEvent未被消耗,則調用View的onTouchEvent?*?
  • ??????????*?ViewGroup中沒有定義onTouchEvent,故做后調用View中的onTouchEvent*/??
  • ??????????if?(onTouchEvent(event))?{??
  • ??????????????return?true;??
  • ??????????}??
  • ??????}??
  • ??????if?(mInputEventConsistencyVerifier?!=?null)?{??
  • ??????????mInputEventConsistencyVerifier.onUnhandledEvent(event,?0);??
  • ??????}??
  • ??????return?false;??
  • ??}??
  • ?

    ?

    小結:

    onInterceptTouchEvent:

    onInterceptTouchEvent是在ViewGroup里面定義的,被ViewGroup.dispatchTouchEvent()調用,用于攔截所有的touch事件。默認返回false,表示不攔截touch事件,ViewGroup.dispatchTouchEvent()會調用子View的dispatchTouchEvent,將touch事件傳遞到子View中。若子View的dispatchTouchEvent?返回false,則ViewGroup的onTouchEvent會被調用;若子View的dispatchTouchEvent?返回true,表示消耗了手勢事件,ViewGroup的onTouchEvent則不會被調用。若ViewGroup.onInterceptTouchEvent()返回true,表示Touch事件被攔截,ViewGroup. dispatchTransformedTouchEvent()函數將被調用,該函數會調用super.dispatchTouchEvent(event),即View的dispatchEvent(),該函數首先會調用View.OnTouchListener.onTouch().若listener未消耗Touch事件,則會調用View.onTouchEvent(). ?

    ?

    onTouchEvent:

    view中定義的方法onTouchEvent默認返回true,表示消耗了一個touch事件,ViewGroup中定義的onTouchEvent默認返回false,表示不處理Touch手勢事件。手勢事件類型包括ACTION_DOWN,ACTION_MOVE,ACTION_UP,ACTION_CANCEL等事件。

    ?

    本節及后續都是參考了一篇國外講義,下載地址:http://download.csdn.net/detail/bigconvience/7376431

    ?

    轉載于:https://www.cnblogs.com/Free-Thinker/p/5501000.html

    總結

    以上是生活随笔為你收集整理的Android的Touch系统简介(一)的全部內容,希望文章能夠幫你解決所遇到的問題。

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