美文网首页
onTouch和 onClick的那些事儿

onTouch和 onClick的那些事儿

作者: ModestStorm | 来源:发表于2020-06-21 14:29 被阅读0次

    转载自:onTouch和 onClick的那些事儿

    image

    PS:在这个全民知识焦虑的时代,每个人都应该明白学习的重要性,应该成为“会学习的人”,而不是做“最勤奋的笨蛋”。

    事件的分发流程可以说基本上已经阐述清楚,在阅读本篇文章之前,请先阅读下面几篇文章:

    还有一个问题是 Android 事件传递过程中 onTouch 和 onClick 事件在整个事件过程中是如何进行事件传递的,下面主要是关于 onTouch 、 onClick 与事件传递过程中调用的先后顺序,将从如下几个方面介绍:

    1. 源码中的 onTouch() 方法

    2. 源码中的 onClick() 方法

    3. onTouch() 与 onClick() 方法之间的关系

    4. 总结

    源码中的 onTouch() 方法

    当要设置触摸事件的监听时,使用到 View 类中的 OnTouchListener 接口,然后通过 setOnClickListener 设置对触摸事件的监听,然后就可以通过具体的事件类型去执行某些操作,onTouch() 方法就是接口 OnTouchListener 中定义的方法,在 View 的 dispatchTouchEvent() 方法中调用,下面时 onTouch方法在源码中的具体调用:

     1//事件分发
     2public boolean dispatchTouchEvent(MotionEvent event) {
     3    ...
     4    //默认返回值
     5    boolean result = false;
     6    ...
     7    //注意判断条件
     8    if (onFilterTouchEventForSecurity(event)) {
     9        if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
    10            result = true;
    11        }
    12
    13        ListenerInfo li = mListenerInfo;
    14        //注意判断条件
    15        if (li != null && li.mOnTouchListener != null
    16                && (mViewFlags & ENABLED_MASK) == ENABLED
    17                && li.mOnTouchListener.onTouch(this, event)) {
    18            result = true;
    19        }
    20
    21        if (!result && onTouchEvent(event)) {
    22            result = true;
    23        }
    24    }
    25   ...
    26    return result;
    27}
    
    

    上述代码中,先来看一下最外面的条件 onFilterTouchEventForSecurity() 方法,只关心该方法的返回值即可,源码如下:

    
     1/**
     2 * 如果事件正常分发返回true,如果事件被丢弃返回false
     3 * @see #getFilterTouchesWhenObscured
     4 */
     5public boolean onFilterTouchEventForSecurity(MotionEvent event) {
     6    //noinspection RedundantIfStatement
     7    if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0
     8            && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) {
     9        // Window is obscured, drop this touch.
    10        return false;
    11    }
    12    return true;
    13}
    
    

    所以该方法正常情况下返回 true,然后关键的条件主要就是 ListenerInfo 是否为 null,mOnTouchListener 是否为 null,以及 onTouch() 方法的返回值,下面是 ListenerInfo 初始化的源码部分,具体如下:

    
     1//getListenerInfo()的具体调用
     2public void setOnTouchListener(OnTouchListener l) {
     3    getListenerInfo().mOnTouchListener = l;
     4}
     5//ListenerInfo的初始化
     6ListenerInfo getListenerInfo() {
     7    if (mListenerInfo != null) {
     8        return mListenerInfo;
     9    }
    10    mListenerInfo = new ListenerInfo();
    11    return mListenerInfo;
    12}
    
    

    显然,当通过 setOnTouchListener() 方法设置触摸事件的监听时就初始化了 ListenerInfo,同在在设置触摸事件监听的时候 mOnTouchListener != null 成立,最后 onTouch() 方法的返回值决定了 dispatchTouchEvent() 方法是否返回 true。所以,当设置了触摸监听事件且 onTouch() 方法返回 true 时,表示事件就此处理也就不再向子 View 传递了,同时,onTouchEvent() 方法也就不再执行,返回 false 则 onTouchEvent() 方法还会执行。

    源码中的 onClick() 方法

    当要设置点击事件的事件监听时,使用到 View 类中的 OnClickListener 接口,然后通过 setOnClickListener 设置对单击事件的监听,然后就可以通过具体的事件类型去执行某些操作,onClick() 方法就是 OnClickListener 接口中定义的方法,在 View 的 onTouchEvent() 方法中调用,在下文中也会进一步得到验证,下面是 onClick() 方法在源码中的具体调用:

     1//事件处理
     2public boolean onTouchEvent(MotionEvent event) {
     3    ...
     4    if (((viewFlags & CLICKABLE) == CLICKABLE ||
     5            (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) ||
     6            (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) {
     7        switch (action) {
     8            case MotionEvent.ACTION_UP:
     9                ...
    10                //如果执行了该方法,其返回值就是onTouchEvent()的返回值
    11                performClick();
    12                ...
    13                break;
    14        }
    15        return true;
    16    }
    17    return false;
    18}
    
    

    上面代码中至少找到了 onClick() 方法的调用位置,下面是 performClick() 方法:

    
     1/**
     2 * 主要回调了 OnClickListener
     3 */
     4public boolean performClick() {
     5    final boolean result;
     6    final ListenerInfo li = mListenerInfo;
     7    if (li != null && li.mOnClickListener != null) {
     8        playSoundEffect(SoundEffectConstants.CLICK);
     9        //调用了OnClickListener接口中的onClick()方法
    10        li.mOnClickListener.onClick(this);
    11        result = true;
    12    } else {
    13        result = false;
    14    }
    15    sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
    16    return result;
    17}
    
    

    显然,只要我们在代码中通过 setOnClickListener() 方法设置了对单击事件的监听,则对应 View 的 onTouchEvent() 方法返回 true,当然事件就此消费,反之返回 false,那么 onTouch 与 onClick 之间的调用顺序如何,它们之间会互相影响吗,下面就会从案列的角度了解它们之间的关系。

    onTouch() 与 onClick() 方法之间的关系

    还是之前的案例,MLinearLayout 嵌套 MRelativeLayout,MRelativeLayout 嵌套 MTextView,三个 View 都只是重写了与它们自身相关的事件分发,然后为 MTextView 设置对触摸事件、单击事件的监听,具体如下:

     1@Override
     2protected void onCreate(Bundle savedInstanceState) {
     3    super.onCreate(savedInstanceState);
     4    setContentView(R.layout.activity_main);
     5
     6    findViewById(R.id.textView).setOnTouchListener(new View.OnTouchListener() {
     7        @Override
     8        public boolean onTouch(View v, MotionEvent event) {
     9            Log.i("Event", "TextView-------onTouch---------------return:" + false);
    10            return false;
    11        }
    12    });
    13
    14    findViewById(R.id.textView).setOnClickListener(new View.OnClickListener() {
    15        @Override
    16        public void onClick(View v) {
    17            Log.i("Event", "TextView-------onClick");
    18    }
    19    });
    20}
    
    
    • 让 onTouch() 返回 false,查看日志如下:
    image

    结论:设置了对触摸事件的监听,onTouch() 方法 false 时 onTouchEvent() 方法在 onTouch() 方法之后执行,事件就此消费,接着接受 ACTION_DOWN 之后的一系列事件,途中使用鼠标,故没有 ACTION_MOVE 事件,还有在 onTouch() 方法返回 false 的情况下 onClick() 执行了。

    • 让 onTouch() 返回 true,查看日志如下:
    image

    结论 :当 onTouch() 返回 true 的时候,正如前面所述 onTouchEvent() 将不会再执行,故 onClick() 也就不会再执行。

    总结

    onTouch() 方法的返回值决定了 onTouchEvent() 方法要不要执行,如果 onTouch() 返回 true,则 onTouchEvent() 不会再执行,返回 false ,则 onTouchEvent() 继续执行,而 onClick() 的回调是在 onTouchEvent() 方法中调用,onTouchEvent() 不执行则 onClick() 不执行。

    相关文章

      网友评论

          本文标题:onTouch和 onClick的那些事儿

          本文链接:https://www.haomeiwen.com/subject/egfaxktx.html