美文网首页Android自定义View
Android View 事件分发

Android View 事件分发

作者: 小菜_charry | 来源:发表于2018-05-09 14:30 被阅读3次

    View 的 dispatchTouchEvent OnTouchListener onTouchEvent OnClickListener 的联系

    通过看源码来分析 View 事件分发过程(下面的代码是精简过后的)

    下面仅针对 View ,ViewGroup 会重写 dispatchTouchEvent,所以会不同。

    public boolean dispatchTouchEvent(MotionEvent event) {
        boolean result = false;
        if (onFilterTouchEventForSecurity(event)) {
            ListenerInfo li = mListenerInfo; // 包含了很多的监听器(包括:OnTouchListener,OnClickListener...)
            if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) { // 这里点调用了 OnTouchListener.onTouch -> true 则 result = true
                result = true;
            }
    
            // result = true 则不走 onTouchEvent 了
            if (!result && onTouchEvent(event)) {
                result = true;
            }
        }
        return result;
    }
    

    可以看到 dispatchTouchEvent :

    • 先调用 OnTouchListener.onTouch
    • 如果 onTouch 返回 false 则
    • 调用 onTouchEvent(event)

    目前没有看到 onClick 的身影,其实是在 onTouchEvent 中:

    下面的代码只是看下源码 「确实是在 ACTION_UP 中调用了 onClick 」

    public boolean onTouchEvent(MotionEvent event) {
        if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) {
            switch (action) {
                case MotionEvent.ACTION_UP:
                    boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0;
                    if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {
                        if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {
                            if (!focusTaken) {
                                if (!post(mPerformClick)) {
                                    performClick(); // 经过一些判断后调用 performClick
                                }
                            }
                        }
                    ...
                    break;
                ...
            }
        }
    }
    
    
    public boolean performClick() {
        final boolean result;
        final ListenerInfo li = mListenerInfo;
        if (li != null && li.mOnClickListener != null) {
            playSoundEffect(SoundEffectConstants.CLICK);
            li.mOnClickListener.onClick(this); // 调用 OnClickListener.onClick
            result = true;
        } else {
            result = false;
        }
        return result;
    }
    

    在 onTouchEvent 中的 ACTION_UP 中判断一些条件是否满足调用点击事件,如果满足并且点击事件监听 mOnClickListener 不为 null 才去调用 OnClickListener.onClick

    所以先后循序:
    dispatchTouchEvent => OnTouchListener => onTouchEvent => OnClickListener

    为什么是在 ACTION_UP 中判断呢?

    1. 只有在抬起的时候才能确定这个事件会不会是 长点击 还是 普通的点击
    2. 只能在其他操作完成之后才能得出是否需要触发 点击事件

    最后一张流程图总结:

    Android View 的事件分发.png

    相关文章

      网友评论

        本文标题:Android View 事件分发

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