android View 事件分发

1、本文的主要内容是对view的事件分发进行详细的分析,view的相对于ViewGroup来说会简单很多

1.1 在onTouchListener onTouch onClickListener 都有的情况下 在onTouchListener 返回为false 日志

09-11 08:01:47.864 6507-6507/? I/Tag: view -> onTouch ->0
09-11 08:01:47.864 6507-6507/? I/Tag: view -> onTouchEvent ->0
09-11 08:01:47.975 6507-6507/? I/Tag: view -> onTouch ->2
09-11 08:01:47.975 6507-6507/? I/Tag: view -> onTouchEvent ->2
09-11 08:01:48.088 6507-6507/? I/Tag: view -> onTouch ->1
09-11 08:01:48.088 6507-6507/? I/Tag: view -> onTouchEvent ->1
09-11 08:01:48.090 6507-6507/? I/Tag: view -> onClick

1.2 在onTouchListener onTouch onClickListener都有的情况在onTouchListener返回为true 日志

09-11 08:19:03.021 7029-7029/? I/Tag: view -> onTouch ->0
09-11 08:19:03.174 7029-7029/? I/Tag: view -> onTouch ->2
09-11 08:19:03.459 7029-7029/? I/Tag: view -> onTouch ->1

1.3 在onTouchListener onClickListener都有的情况在onTouchListener返回为true 日志

09-11 08:31:31.400 7620-7620/? I/Tag: view -> onTouch ->0
09-11 08:31:31.441 7620-7620/? I/Tag: view -> onTouch ->2
09-11 08:31:31.667 7620-7620/? I/Tag: view -> onTouch ->1

2、下面对源码进行分析

2.1 找到view的源码 dispatchTouchEvent(MotionEvent event) 这个方法 所有的view和ViewGroup的事件分发和响应都是从这里开始的可能不同的sdk版本源码有些区别 我这里是7.1.1的

以下的有出现的代码都是需要重点关注的 其他的可以不需要关注

boolean result = false 这句 这是dispatchTouchEvent返回值

ListenerInfo li = mListenerInfo;

这个ListenerInfo其实就是整个View中所有接口存放的位置

最重要的两个方法之一


if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;
    }

这里li已经赋值了不可能等于空

mOnTouchListener 这个方法就是你是否实现了接口 这边我们也不为空

(mViewFlags & ENABLED_MASK) == ENABLED 这个是你的view是否可用 也就是可不可以点击
一般默认都是为可用 这里也是 true

li.mOnTouchListener.onTouch(this, event) 这个方法就是实现的方法

为什么onTouch是第一个调用也是这个原因 这里在1.1的情形中是返回false

所以 result = true;这个if判断不会进来

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

因为上面 if判断没进去 result 还是 false onTouchEvent(event)这里就调用了onTouchEvent 的方法

现在走到onTouchEvent内部看看 在这里面如果默认返回super.onTouchEvent(event) 这里都是返回true

在这个方法里会看到一个方法叫performClick() 这个就是点击事件 我们进到里面看看

 if (!post(mPerformClick)) {
   performClick();
}
......
public boolean performClick() {
        final boolean result;
        final ListenerInfo li = mListenerInfo;
        if (li != null && li.mOnClickListener != null) {
            playSoundEffect(SoundEffectConstants.CLICK);
            li.mOnClickListener.onClick(this);//这里就是onClick最后走的原因
            result = true;
        } else {
            result = false;
        }

        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
        return result;
}

3 看过源码之后我们可以得出上面三种情况的结论

3.1 第一种 全部都是默认实现的情况 首先走dispatchTouchEvent中第一个if判断的 li.mOnTouchListener.onTouch(this, event) ,其次走第二个if判断 onTouchEvent(event)这个方法 最后走onTouchEvent中的performClick()完成了一个view的事件流程

3.2 第二种 onTouchListener 返回值为true 我们刚刚看过了源码也知道如果li.mOnTouchListener.onTouch(this, event)返回值为true 就说明第一个if判断成立 result = true; 就会为true 这样会导致第二个if判断进不去 所以只会出现三个onTouch的情况

3.3 第三种 onTouchEvent 返回true 这里就不会调用super.onTouchEvent(event) 所以不会走父类的performClick()方法 所以不会出现onClick打印

4、这里先不管result返回回去到底为什么, 我们只需要关注这里面的代码的流程就行,在下一节ViewGroup的事件分发会提到这个result返回值的用处

你可能感兴趣的:(android View 事件分发)