美文网首页
事件分发-Click Touch监听器源码分析

事件分发-Click Touch监听器源码分析

作者: 杨0612 | 来源:发表于2020-05-19 11:03 被阅读0次

    分析下OnClickListener,OnLongClickListener,OnTouchListener,onTouchEvent这4个方法的调用关系。
    源码分析基于Android-23

    1.简述方法作用

    1.1 OnTouchListener以及 onTouchEvent
    都是可以监听Touch事件,区别在于,前者是通过setOnTouchListener的方式来使用,后者是view的方法,重写即可,常用在自定义控件;
    1.2 OnClickListener
    监听点击事件;
    1.3 OnLongClickListener
    监听长按事件。

    2.OnTouchListener onTouchEvent两者的关系

    2.View.dispatchTouchEvent

    (1)dispatchTouchEvent,是事件处理的入口;
    (2)当设置了setOnTouchListener,那么li.mOnTouchListener就不为空,onTouch方法会被触发并且返回true,那么onTouchEvent就不会被触发;
    (3)没有设置setOnTouchListener或者onTouch方法返回false,那么onTouchEvent就不会被触发;
    (4)返回true比较消费了事件;
    (5)可以看出mOnTouchListener onTouch方法优先级比onTouchEvent高;

    public boolean dispatchTouchEvent(MotionEvent event) {
            ......
            if (onFilterTouchEventForSecurity(event)) {
                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;
                }
            }
           ......
            return result;
        }
    

    3.OnTouchEvent OnClickListener、OnLongClickListener三者的关系

    View.onTouchEvent

    (1)主要看down、move、up事件的处理;
    (2)down事件,如果view被滑动控件包裹,则isInScrollingContainer为true,需要通过延时任务mPendingCheckForTap判断是tap事件还是滑动事件,如果在延时时间100毫秒内没有任何滑动,则发送400毫秒延时任务执行长按,有任何滑动都将移除mPendingCheckForTap;
    (3)上述(2)没有包裹在滑动控件中,则触发checkForLongClick发送500毫秒延时任务执行长按;
    (4)up事件,如果长按事件没有被触发或者返回false,mHasPerformedLongPress 则为false,将移除长按任务,接着执行performClick,通过从ViewRootImpl得到的handle往主线程队列发送点击任务,等待被执行,由此可见长按事件被消费了,那么点击事件就无法执行;
    (5)performClick内部就是触发li.mOnClickListener.onClick,这里就不展开了;
    (6)move事件,移除tap任务removeTapCallback,如果发送了延时任务执行长按,也需要移除removeLongPressCallback;
    (7)当onTouchEvent被触发,onClick、onLongClick才有可能被执行,如果onLongClick消费了时间,那么onClick将无法执行;

    public boolean onTouchEvent(MotionEvent event) {
                ......
                switch (action) {
                    case MotionEvent.ACTION_UP:
                            ......
                            if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {
                                removeLongPressCallback();
                                ......
                               performClick();
                            }
                        ......
                        break;
    
                    case MotionEvent.ACTION_DOWN:
                        ......
                        if (isInScrollingContainer) {
                            if (mPendingCheckForTap == null) {
                                mPendingCheckForTap = new CheckForTap();
                            }
                            postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
                        } else {
                            checkForLongClick(0);
                        }
                        break;
    
                    case MotionEvent.ACTION_CANCEL:
    
                        removeTapCallback();
                        removeLongPressCallback();
                        ......
                        break;
    
                    case MotionEvent.ACTION_MOVE:
                        ......
                        if (!pointInView(x, y, mTouchSlop)) {
                            removeTapCallback();
                            if ((mPrivateFlags & PFLAG_PRESSED) != 0) {
                                  ......
                                removeLongPressCallback();
                            }
                        }
                        break;
                }
                return true;
            }
            return false;
        }
    
    5.总结

    (1) OnTouchListener onTouch优先级比onTouchEvent高;
    (2)当onTouchEvent被触发,onClick、onLongClick才有可能被执行,
    (3)当onLongClick消费了事件,那么onClick将无法执行;
    (4)点击事件实现,在up事件时,利用ViewRootImpl构建的handler,往主线程MessageQueue发一个runnable点击任务,等待被分发执行;
    (5) 长按事件实现,发送100毫秒延时任务判断是tap还是滑动,如果是tap,则再发送400毫秒延时任务执行长按;

    有分析不对的地方请指出,互相学习,谢谢哦!

    相关文章

      网友评论

          本文标题:事件分发-Click Touch监听器源码分析

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