欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android事件分發(fā)機(jī)制全面解析

 更新時(shí)間:2021年03月27日 09:10:37   作者:ezy  
這篇文章主要介紹了Android事件分發(fā)機(jī)制全面解析,幫助大家更好的理解和學(xué)習(xí)使用Android開發(fā),感興趣的朋友可以了解下

事件分發(fā)機(jī)制

事件分發(fā)機(jī)制的兩個(gè)階段:

  • 分發(fā):事件從父視圖往子視圖分發(fā),被攔截后不再傳遞,進(jìn)入回溯階段
  • 回溯:事件從子視圖往父視圖回溯,被消費(fèi)后不再回溯

關(guān)鍵方法:

  • ViewGroup.dispatchTouchEvent 往子視圖分發(fā)事件
  • ViewGroup.onInterceptTouchEvent 返回 true 表示攔截分發(fā)事件,不再傳遞,進(jìn)入當(dāng)前視圖 onTouchEvent
  • View.dispatchTouchEvent 默認(rèn)事件分發(fā),調(diào)用 onTouchEvent
  • View.onTouchEvent 通常重載此方法處理事件,返回 true 表示消費(fèi)事件,不再傳遞,返回 false 往上回溯
  • ViewParent.requestDisallowInterceptTouchEvent(true) 可以確保事件分發(fā)到子視圖前不被攔截

假設(shè)視圖層次為 A.B.C.D,事件分發(fā)回溯默認(rèn)過程為:

A.dispatchTouchEvent
 B.dispatchTouchEvent
  C.dispatchTouchEvent
   D.dispatchTouchEvent
   D.onTouchEvent 
  C.onTouchEvent
 B.onTouchEvent
A.onTouchEvent

假設(shè) B 攔截了事件:

A.dispatchTouchEvent
 B.dispatchTouchEvent -> B.onInterceptTouchEvent 
 B.onTouchEvent
A.onTouchEvent

假設(shè) C.onTouchEvent 消費(fèi)了事件:

A.dispatchTouchEvent
 B.dispatchTouchEvent
  C.dispatchTouchEvent
   D.dispatchTouchEvent
   D.onTouchEvent 
  C.onTouchEvent 

事件分發(fā)機(jī)制偽代碼:

class Activity { 
  fun dispatchTouchEvent(ev) {
    if (parent.dispatchTouchEvent(ev)) {
      return true
    }
    return onTouchEvent(ev)
  }
  fun onTouchEvent(ev):Boolean {...}
} 

class ViewGroup : View { 
  fun dispatchTouchEvent(ev) { 
    var handled = false
    if (!onInterceptTouchEvent(ev)) {
      handled = child.dispatchTouchEvent(ev)
    } 
    return handled || super.dispatchTouchEvent(ev) 
  } 
  fun onInterceptTouchEvent(ev):Boolean {...} 
  fun onTouchEvent(ev):Boolean {...}
} 

class View { 
  fun dispatchTouchEvent(ev) { 
    var result = false
    if (handleScrollBarDragging(ev)) {
      result = true
    }
    if (!result && mOnTouchListener.onTouch(ev)) {
      result = true
    } 
    if (!result && onTouchEvent(ev)) {
      result = true
    }
    return result
  } 
  fun onTouchEvent(ev):Boolean {...}
}

ViewGroup.dispatchTouchEvent 源碼分析

1.開始:ACTION_DOWN 事件開始一個(gè)新的事件序列,清除之前觸摸狀態(tài)
2.攔截:

2.1. 非 ACTION_DOWN 事件如果當(dāng)前沒有子視圖消費(fèi)事件,表示事件序列已被攔截
2.2. 事件未被攔截且子視圖未申請(qǐng)禁止攔截時(shí),再通過 onInterceptTouchEvent 嘗試攔截事件

3.分發(fā):如果事件未被攔截也未被取消,就遍歷子視圖分發(fā)事件,并尋找當(dāng)前事件的觸摸目標(biāo)

3.1. 在觸摸目標(biāo)鏈表中找到了可以消費(fèi)當(dāng)前事件的視圖觸摸目標(biāo) -> 將其標(biāo)記為當(dāng)前觸摸目標(biāo),延遲到步驟4分發(fā)事件給它
3.2. 一個(gè)不在觸摸目標(biāo)鏈表中的視圖消費(fèi)了事件 -> 將其標(biāo)記為當(dāng)前觸摸目標(biāo),并設(shè)置為觸摸目標(biāo)鏈表表頭
3.3. 未找到消費(fèi)當(dāng)前事件的視圖,但觸摸目標(biāo)鏈表不為空 -> 將觸摸目標(biāo)鏈表末端標(biāo)記為當(dāng)前觸摸目標(biāo)

4.分發(fā):觸摸目標(biāo)鏈表不為空,則遍歷觸摸目標(biāo)鏈嘗試傳遞事件或取消觸摸目標(biāo)(事件被攔截)
5.回溯:觸摸目標(biāo)鏈表為空(當(dāng)前沒有子視圖消耗事件序列),則將事件轉(zhuǎn)發(fā)給基類 dispatchTouchEvent 處理
注:觸摸目標(biāo)(ViewGourp.TouchTarget) 描述一個(gè)被觸摸的子視圖和它捕獲的指針ids

public boolean dispatchTouchEvent(MotionEvent ev) {
  // 省略代碼 ...
  boolean handled = false;
  if (onFilterTouchEventForSecurity(ev)) {
   
    if (actionMasked == MotionEvent.ACTION_DOWN) { 
      // 1. `ACTION_DOWN` 事件開始一個(gè)新的事件序列,清除之前觸摸狀態(tài) ...
    }
    // 省略代碼 ... 
    final boolean intercepted;
    // 2. 攔截
    if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) {
      final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
      if (!disallowIntercept) {
        // 2.2. 事件未被攔截且子視圖未申請(qǐng)禁止攔截時(shí),再通過 onInterceptTouchEvent 嘗試攔截事件
        intercepted = onInterceptTouchEvent(ev);
        // 省略代碼 ...
      } else {
        intercepted = false;
      }
    } else { 
      // 2.1. 非 `ACTION_DOWN` 事件如果當(dāng)前沒有子視圖消費(fèi)事件,表示事件序列已被攔截
      intercepted = true;
    }
    // 省略代碼 ... 
    if (!canceled && !intercepted) {
      // 省略代碼 ... 
          // 3. 分發(fā):如果事件未被攔截也未被取消,就遍歷子視圖分發(fā)事件,并尋找當(dāng)前事件的觸摸目標(biāo)
          for (int i = childrenCount - 1; i >= 0; i--) {
            // 省略代碼 ... 
            newTouchTarget = getTouchTarget(child);
            if (newTouchTarget != null) { 
              // 3.1. 在觸摸目標(biāo)鏈表中找到了可以消費(fèi)當(dāng)前事件的視圖觸摸目標(biāo) -> 將其標(biāo)記為當(dāng)前觸摸目標(biāo),延遲到步驟4分發(fā)事件給它
              // 省略代碼 ... 
              break;
            }
            if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
              // 省略代碼 ...
              // 3.2. 一個(gè)不在觸摸目標(biāo)鏈表中的視圖消費(fèi)了事件 -> 將其標(biāo)記為當(dāng)前觸摸目標(biāo),并設(shè)置為觸摸目標(biāo)鏈表表頭
              newTouchTarget = addTouchTarget(child, idBitsToAssign);
              alreadyDispatchedToNewTouchTarget = true;
              break;
            }
            // 省略代碼 ...
          }
          
        if (newTouchTarget == null && mFirstTouchTarget != null) {
          // 3.3. 未找到消費(fèi)當(dāng)前事件的視圖,但觸摸目標(biāo)鏈表不為空 -> 將觸摸目標(biāo)鏈表末端標(biāo)記為當(dāng)前觸摸目標(biāo) 
          newTouchTarget = mFirstTouchTarget;
          while (newTouchTarget.next != null) {
            newTouchTarget = newTouchTarget.next;
          }
          newTouchTarget.pointerIdBits |= idBitsToAssign;
        }
      // 省略代碼 ... 
    }

    // Dispatch to touch targets.
    if (mFirstTouchTarget == null) {
      // 5. 回溯:觸摸目標(biāo)鏈表為空(當(dāng)前沒有子視圖消耗事件序列),則將事件轉(zhuǎn)發(fā)給基類 dispatchTouchEvent 處理
      handled = dispatchTransformedTouchEvent(ev, canceled, null, TouchTarget.ALL_POINTER_IDS);
    } else {
      // 省略代碼 ... 
      // 4. 分發(fā):觸摸目標(biāo)鏈表不為空,則遍歷觸摸目標(biāo)鏈嘗試傳遞事件或取消觸摸目標(biāo)(事件被攔截)
      TouchTarget target = mFirstTouchTarget;
      while (target != null) { 
        final TouchTarget next = target.next; 
        // 省略代碼 ... 
          if (dispatchTransformedTouchEvent(ev, cancelChild, target.child, target.pointerIdBits)) {
            handled = true;
          } 
        // 省略代碼 ... 
        target = next;
      }
    }
    // 省略代碼 ... 
  }
  // 省略代碼 ...
  return handled;
}

View.dispatchTouchEvent 和 View.onTouchEvent 源碼分析

  • 滾動(dòng)條消費(fèi)鼠標(biāo)事件
  • OnTouchListener 消費(fèi)觸摸事件
  • onTouchEvent 消費(fèi)觸摸事件

TouchDelegate 消費(fèi)觸摸事件

public boolean dispatchTouchEvent(MotionEvent event) {
  // 省略代碼 ...
  boolean result = false;
  
  // 省略代碼 ... 
  if (onFilterTouchEventForSecurity(event)) {
    // 滾動(dòng)條消費(fèi)鼠標(biāo)事件
    if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
      result = true;
    } 
    // OnTouchListener 消費(fèi)觸摸事件
    ListenerInfo li = mListenerInfo;
    if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this, event)) {
      result = true;
    } 
    // View默認(rèn)的事件處理邏輯,事件可能在其中被設(shè)置的 TouchDelegate 消費(fèi)
    if (!result && onTouchEvent(event)) {
      result = true;
    }
  }
  // 省略代碼 ... 
  return result;
} 

public boolean onTouchEvent(MotionEvent event) {
  // 省略代碼 ... 
  if (mTouchDelegate != null) {
    // TouchDelegate 消費(fèi)觸摸事件
    if (mTouchDelegate.onTouchEvent(event)) {
      return true;
    }
  }
  // 省略代碼 ... 
  return false;
}

以上就是Android事件分發(fā)機(jī)制全面解析的詳細(xì)內(nèi)容,更多關(guān)于Android事件分發(fā)機(jī)制的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論