1. 程式人生 > 其它 >Android 事件分發機制原始碼分析

Android 事件分發機制原始碼分析

if(MotionEvent.ACTION_DOWN || mFirstTouchTarget != null){
     //初次的down事件到來的時候,只有父view具有決定事件是否攔截的權利。因為此時的disallowIntercept初始值是false,原因是down事件之前會重置這個標誌位
     final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
     //第一個down進來下面這個if條件是成立的,因此父view的onInterceptTouchEvent方法就決定了是否攔截
     if(!disallowIntercept){
         intercepted = onInterceptTouchEvent(ev)
     }else{
         //這個條件是子view要求父view不要攔截,其實就是後續的move和up事件不要攔截,因為能進到這個地方不可能是down事件並且mFirstTouchTarget != null
         intercepted = false;
     }
}else{
    //進到這個地方說明事件是move或者up並且mFirstTouchTarget == null。
    //move或者up能進到這個地方說明mFirstTouchTarget == null,那麼就意味著要麼down被父view消費了(down事件被父view攔截了或者子view不處理down事件又把down事件交給父view處理)
    //要麼就是在move或者up的事件子view要求父view進行攔截並且父view攔截了,這樣也會導致mFirstTouchTarget == null成立。這樣的話子view就再也拿不到事件了
    intercepted = true
}
//新的事件會重置這兩個值
TouchTarget newTouchTarget = null;
boolean alreadyDispatchedToNewTouchTarget = false;
//只有不攔截才會命中
if(!canceled && !intercepted){
     //只有down事件才會進行分發
     if (actionMasked == MotionEvent.ACTION_DOWN){
          for(){
             //利用迴圈遍歷按住的子view
             if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
                  //如果找到了處理down事件的子view 就會在addTouchTarget方法裡面把 mFirstTouchTarget的值設定成非空
                  newTouchTarget = addTouchTarget(child, idBitsToAssign);
                  //把已經消費的標記為設定成true
                  alreadyDispatchedToNewTouchTarget = true;
                  break;
             }
          }
     }
}
//上面已經解釋過mFirstTouchTarget==null的原因了,1、down事件被父view消費掉了 2、子view的move事件交給了父view攔截並且攔截了
if(mFirstTouchTarget == null){
    //自己處理事件
    handled = dispatchTransformedTouchEvent(ev, canceled, null, TouchTarget.ALL_POINTER_IDS);
}else {
    //子view處理事件
    TouchTarget target = mFirstTouchTarget;
    while(target != null){
         if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
             //如果當前事件是down並且down事件被子view處理了這個就會成立
             handled = true;
         }else{
            //事件來的時候會重置alreadyDispatchedToNewTouchTarget = false  能進到這裡說明1、down事件被子view處理並且此時的事件不是down事件。
            //如果move或者up事件被攔截了cancelChild則是true否則false
            final boolean cancelChild = resetCancelNextUpFlag(target.child)|| intercepted;
            //交給自己或者子view去處理
            if (dispatchTransformedTouchEvent(ev, cancelChild, target.child, target.pointerIdBits)) {
                     handled = true;
             }
            //如果是自己處理也就是move事件被父view攔截了
            if (cancelChild) {
                //mFirstTouchTarget設定成next 單指為null
                mFirstTouchTarget = next
             }
         }
          target = next;
      }
    }
}