Android--事件分发机制

Android中事件分发涉及到三个View,Activity ViewGroup View,而事件的传递顺序是从Activity-->ViewGroup-->View;涉及到三个方法

dispatchTouchEvent()  onTouchEvent()  onInterceptTouEvent。之后我会从源码的角度来分析事件分发的过程

一、Activity的事件分发

我们先从事件的开头来介绍。当有一个action发生时,最先执行的就是Activity中的dispatchTouchEvent,源码如下图

public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            onUserInteraction();
        }
        if (getWindow().superDispatchTouchEvent(ev)) {
            return true;
        }
        return onTouchEvent(ev);
    }

dispatchTouchEvent方法是有一个布尔的返回值,当返回true,表示事件在当前Activity中被处理掉了,不在向下进行事件的分发操作了。而源码中getWindow所得到的类是一个抽象类,所以我们需要找到具体的实现类,而Activity的布局图如下,PhoneWindow其实就是Window抽象类的实现类。

我们去看PhoneWindow中的superDispatchTouchEvent,源码如下

@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
       return mDecor.superDispatchTouchEvent(event);
}

而mDecor就是上图中DecorView,我们查看DecorView中的superDispathchTouchEvent,源码如下

public boolean superDispatchTouchEvent(MotionEvent event) {
        return super.dispatchTouchEvent(event);
}

DecorView的父类是FrameLayout,而FrameLayout的父类是ViewGroup,所以,事件到了这里就传递到了ViewGroup中的dispatchTouchEvent

二、ViewGroup中的事件分发

接着上面说的,我们来查看ViewGroup中的dispatchTouchEvent,我从中挑出重点部分来说

事件的拦截 onInterceptTouchEvent,从源码中我们可以看到,onInterceptTouchEvent我们是可以覆写的,intercepted就是我们覆写后的值

            final boolean intercepted;
            if (actionMasked == MotionEvent.ACTION_DOWN
                    || mFirstTouchTarget != null) {
                final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
                if (!disallowIntercept) {
                    intercepted = onInterceptTouchEvent(ev);
                    ev.setAction(action); // restore action in case it was changed
                } else {
                    intercepted = false;
                }
            } else {
                // There are no touch targets and this action is not an initial down
                // so this view group continues to intercept touches.
                intercepted = true;
            }

我们继续向下看源码,看到一个for循环,进行子View的遍历

final View[] children = mChildren;
for (int i = childrenCount - 1; i >= 0; i--) {
    final int childIndex = getAndVerifyPreorderedIndex(
            childrenCount, i, customOrder);
    final View child = getAndVerifyPreorderedView(
            preorderedList, children, childIndex);

我们在for循环中发现了dispatchTransformedTouchEvent方法,从方法名的字面翻译就是分发传递事件,我们点进去查看源码,发现源码中有两个比较重要的代码,无论是child,还是super其实都是View,所以事件传递到了View中

handled = child.dispatchTouchEvent(event);
handled = super.dispatchTouchEvent(event);

三、View中的事件分发

接着上面,我们查看View中的dispatchTouchEvent源码发现,这个方法的返回值是result变量,而使result值改变的位置有三个,如下

if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
    result = true;
}
//noinspection SimplifiableIfStatement
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;
}

第一个if:如果当前View可用并且是当做滚动条来处理,则返回true

第二个if:(1)OnTouchListener监听对象不为空

                 (2)当前view可用

                 (3)覆写了onTouch方法

第三个if:执行了onTouchEvent方法

我们查看onTouchEvent方法,发现只要clickable为true就会返回true。表示如果当前view可以点击,那么当前view就会处理action

 

到这里,事件分发机制的源码就分析完了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值