事件分发机制(三)--View

285 阅读2分钟

「这是我参与11月更文挑战的第25天,活动详情查看:2021最后一次更文挑战

1. View.dispatchTouchEvent()

View的关键方法是onTounchEvent(),是事件处理的主要步骤,也是事件分发流程的最后步骤。View也有dispatchTounchEvent(),在方法中主要是确定事件该交由谁来处理,是onTouchEvent()处理还是onTouchListener处理

  • 判断当前事件是否要求传递给已经获取焦点的View
public final boolean dispatchPointerEvent(MotionEvent event) {
  if (event.isTouchEvent()) {
    return dispatchTouchEvent(event);
  } else {
    return dispatchGenericMotionEvent(event);
  }
}
  • 判断当前View是否可以接收事件的判断,如果可以则进行分发,事件分发有3个步骤: (1) 首先是handleScrollBarDragging(),处理滚动条事件的,该方法只处理来自鼠标的事件,因此一般情况下都返回false

(2) 然后是OnTouchListener处理,并记录处理结果,如果我们在onTouchListener中返回了true,即消费了事件的话,那么该事件将不再进入View.onTouchEvent()。也就意味着无法处理点击、长按等事件处理了。

(3) 两者是否已经消费了事件,如果是的话则不再将事件分发给onTouchEvent(),否则再将事件交给onTouchEvent()去处理

if (onFilterTouchEventForSecurity(event)) {
  if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
    result = true;
  }
  ListenerInfo li = mListenerInfo;
  if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this, event)) {
    result = true;
  }
  if (!result && onTouchEvent(event)) {
    result = true;
  }
}

2. View.onTouchEvent()

  • (1) clickable:先判断当前View是否允许点击
  • (2) 判断View是否是处于不可用状态,如果不可用的话则直接将是否可点击作为是否消费事件返回
  • (3) 将事件交给代理去处理,如果代理处理了事件,那么事件分发到此结束。否则就继续往下,使用默认的实现对事件进行处理
public boolean onTouchEvent(MotionEvent event) {
  ...
  // (1) 
  final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE
                || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)
                || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE;
  // (2) 
  if ((viewFlags & ENABLED_MASK) == DISABLED
                && (mPrivateFlags4 & PFLAG4_ALLOW_CLICK_WHEN_DISABLED) == 0) {
    if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {
      setPressed(false);
    }
    mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
    return clickable;
  }
  // (3) 
  if (mTouchDelegate != null) {
    if (mTouchDelegate.onTouchEvent(event)) {
      return true;
    }
  }
  ...
  return false;
}

3. 总结

  • View负责事件消费事件处理
  • 调用mOnTouchListener的onTouch
  • 如果消费,直接返回true,否则,继续调用onTouchEvent方法
  • 如果为启用的(enable),返回可点击(clickable),否则,调用mTouchDelegate的onTouchEvent
  • 如果消费,直接返回true ,如果可点击(clickable), 进行事件流(ACTION_DOWN,ACTION_MOVE,ACTION_UP,ACTION_CANCEL)处理,返回true,否则返回false

View.png