问题:

View的onTouchEvent,OnLongClickListener,OnClickListener,OnTouchListener几者的执行顺序是怎样的?

回答:

这三者的响应顺序依此是diapatchTouchEvent > onTouchListener.onTouch > onTouchEvent > OnLongClickListener > onClickListener,其中任一环节处理事情后,事情则不持续向下分发,View内部的事情处理流程如下图:

面试串讲008-View的OnTouchEvent,OnClickListener,OnTouchListener三者的执行顺序

可以看出不管OnTouchListener.onTouch,onTouchEvent仍是OnClickListener.onClick,三者任一回来true,即代表事情被当时View耗费,假如当时View不处理事情,则该事情会向上冒泡,终究被ViewRootImpl处理。

解析:

关于响应事情的View而言,在不考虑父布局拦截事情的前提下,事情流入View的dispatchTouchEvent,在View的onTouchEvent中进行处理。针对一个View而言,咱们需要自己处理触摸事情时,通常情况下有三种方式:

  • 设置OnTouchListener
  • 重写onTouchEvent
  • 设置OnClickListener

那么这三者有什么区别呢?触发顺序是怎样的呢?

设置OnTouchListener

为View设置OnTouchListener

view.setOnTouchListener(new View.OnTouchListener() {
  @Override
  public boolean onTouch(View v, MotionEvent event) {
    return true;
   }
});

那么咱们来看下OnTouchListener.onTouch是在哪里调用的?

public void setOnTouchListener(OnTouchListener l) {
  getListenerInfo().mOnTouchListener = l;
}

面试串讲008-View的OnTouchEvent,OnClickListener,OnTouchListener三者的执行顺序

可以看出dispatchTouchEvent会判断是否设置了OnTouchListener,假如设置了的话,就把事情先转交给OnTouchListener处理,OnTouchListener.onTouch回来false再持续分发。

设置OnClickListener

为View设置OnClickListener的代码如下所示:

view.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View v) {
   }
});

那么咱们来看下OnClickListener.onClick是在哪里调用的?

public void setOnClickListener(@Nullable OnClickListener l) {
  if (!isClickable()) {
    setClickable(true);
   }
  getListenerInfo().mOnClickListener = l;
}

面试串讲008-View的OnTouchEvent,OnClickListener,OnTouchListener三者的执行顺序

可以看到OnClickListener.onClick是在performClick中调用的,而performClick是在onTouchEvent的ACTION_UP中经过performClickInternal调用的,代码如下:

面试串讲008-View的OnTouchEvent,OnClickListener,OnTouchListener三者的执行顺序

onTouchEvent

从dispatchTouchEvent中可以看到当不设置OnTouchListener或许OnTouchListener.onTouch回来false时,会将事情交给View的onTouchEvent处理,代码如下:

面试串讲008-View的OnTouchEvent,OnClickListener,OnTouchListener三者的执行顺序