view的事件分发之onTouch和onClick

Android事件分发

view的事件分发之onTouch和onClick

项目中我们经常会遇到对一个控件重写两个方法setOnClickListener和setOnTouchListener来监听这个控件的点击事件和动作,但是如果对于一个控件的这两个方法同时监听,会怎样去执行呢?


->我们先对默认可以点击的控件,如Button进行分析。
我们在一个activity中放一个Button控件,然后设置监听

button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.e(tag, "onClick");
        }
    });


    button.setOnTouchListener(new View.OnTouchListener() {
                                  @Override
                                  public boolean onTouch(View v, MotionEvent event) {
                                      switch (event.getAction()) {
                                          case MotionEvent.ACTION_DOWN:
                                              Log.i(tag, "viewbutton-onTouch-ACTION_DOWN...");
                                              break;
                                          case MotionEvent.ACTION_UP:
                                              Log.i(tag, "viewbutton-onTouch-ACTION_UP...");
                                              break;
                                          default:
                                              break;
                                      }

                                      return false;
                                  }
                              }

    );

点击此控件的话,是onTouch先执行,然后执行onClick,如果onTouch返回true,那么只执行onClick。
我们从dispatchTouchEvent源码得知

    if (onFilterTouchEventForSecurity(event)) {
        //noinspection SimplifiableIfStatement
        ListenerInfo li = mListenerInfo;
        if (li != null && 
        // 监听事件不为空
        li.mOnTouchListener != null
            // enable为true
                && (mViewFlags & ENABLED_MASK) == ENABLED
                // 这里会先执行
                && li.mOnTouchListener.onTouch(this, event)) {
            result = true;
        }

        if (!result && onTouchEvent(event)) {
            result = true;
        }
    }

在我标注的地方会先执行,即 onTouch(this, event),如果返回true的话,就不会执行下面的判断条件,就是不执行onTouchEvent(event)。但是为什么不执行onClick呢?
我们在查看onTouchEvent(event)的源码的时候会发现

if (mPerformClick == null) {
    mPerformClick = new PerformClick();
}
if (!post(mPerformClick)) {
    performClick();
 }

而在performClick()中有:

if (li != null && li.mOnClickListener != null) {
        playSoundEffect(SoundEffectConstants.CLICK);
        li.mOnClickListener.onClick(this);
        result = true;
    } else {
        result = false;
    }

就是执行onClick。所以我们的流程就是
先调用控件的dispatchTouchEvent(),然后执行onTouch(),如果onTouch()返回false的话,执行控件的onTouchEvent方法,继而执行onClick方法。

->我们现在对默认不可点击的事件进行分析,如ImageView:
执行顺序其实和上面是一样的,但是在onTouchEvent方法中,有这么一个判断条件:

if (((viewFlags & CLICKABLE) == CLICKABLE ||
            (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) ||
            (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) {

先判断时候可以点击,如果不能就不会进入,然后就不会执行onClick方法。如果想让此种view能执行点击事件,可以设置setClickable(true);

你可能感兴趣的:(view的事件分发之onTouch和onClick)