【Android】言简意赅的View分发机制

本文详细解析了Android中View的事件分发机制,包括View树的概念、Touch事件的组成,以及从Activity#dispatchTouchEvent到ViewGroup#dispatchTouchEvent的分发流程。重点介绍了ViewGroup如何判断是否拦截事件,以及子View如何处理Touch事件的过程。
摘要由CSDN通过智能技术生成


页面的布局是由ViewGroup或View叠加的显示的。当一个MotionEvent产生以后,系统需要一个具体的View去响应这个事件,也就是把这个事件传递给一个View去处理,这个传递过程就是View的分发。
从宏观的角度看,他的传递过程应该是Activity->PhoneWindow->DecorView->ViewGroup->View…,这是一个整体的分发过程,但是从微观的实现角度讲,绍复杂一些。下面对这个过程进行一个详尽的描述。

一、基础概念

在说分发流程前先说两个常见的概念,View树和Touch事件,接下来简要描述一下。

1、View树

事件分发中只有两个主角ViewGroup和View,ViewGroup和View的关系可以描述成一个树状结构。根节点为Activity布局中包含的一个ViewGroup,往下延申有若干个ViewGroup或View节点,每个ViewGroup节点下又可延伸若干个ViewGroup或View节点,以此类推。事件分发机制的核心可以说就是View树的一个遍历过程。

2、Touch事件

Touch事件由Action_Down、Action_Move和Action_Up组成,具体的含义不说了,从字面意思应该就能理解。Down和Up事件都只有一个,Move有若干个,也可以是0个,Touch事件可被封装成MotionEvent对象,在onTouchEvent回调中传递给对应的Activity。

二、分发流程

View的分发流程中有三个重要的方法,onInterceptTouchEvent、dispatchTouchEvent、onTouchEvent,其中ViewGroup中包含onInterceptTouchEvent、dispatchTouchEvent、onTouchEvent三个相关事件,View包含dispatchTouchEvent、onTouchEvent两个相关事件。其中,dispatchTouchEvent用于进行事件的分发,onInterceptTouchEvent用于判断是否拦截某个事件,onTouchEvent在dispatchTouchEvent方法中调用,用来处理点击事件。下面从源码的角度来分部来分析下具体的分发流程。

1、Activity#dispatchTouchEvent源码

当一个点击操作发生时,事件肯定最先传递给当前的Activity,然后调用Activity的dispatchTouchEvent来进行事件分发。

// Activity#dispatchTouchEvent
public boolean dispatchTouchEvent(MotionEvent ev) {
   
    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
   
        //该方法是个空实现
        onUserInteraction(); 
    }
    
    //事件的分发是由window的superDispatchTouchEvent方法完成的
    if (getWindow().superDispatchTouchEvent(ev)) {
   
        return true; 
    }
    return onTouchEvent(ev);
}

// Window#superDispatchTouchEvent
// 可以看到该方法是个抽象方法,然而Window只有一个实现类PhoneWindow,下面来看看PhoneWindow内该方法的实现
public abstract boolean superDispatchTouchEvent(MotionEvent event);

// PhoneWindow#superDispatchTouchEvent
@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
   
    // 应该很清晰了,PhoneWindow将事件传递给了DecorView
    return mDecor.superDispatchTouchEvent(event);
}

总结:当点击事件来临的时候,首先会调用Activity的dispatchTouchEvent,而实际具体的工作是由Activity内部的Window来完成的。Window又是个抽象类,其具体实现再PhoneWindow中,PhoneWindow又将这个事件传递给了DecorView来处理。这个DecorView在之前的View绘制流程的文章中说过,也就是我们setContentView设置的View,它是所有View的顶层View,一般来说是一个ViewGroup。

2、ViewGroup#dispatchTouchEvent源码

注:代码中需要知道的地方均以Focus开头标记出来,在代码后分别分析。由于ViewGroup#dispatchTouchEvent太长,现按步骤分别来看。

步骤一:判断当前ViewGroup是否要拦截事件

ViewGroup#dispatchTouchEvent
// Check for interception.
final boolean intercepted;
// Focus one
if (actionMasked == MotionEvent.ACTION_DOWN
	|| mFirstTouchTarget != null) {
   
    // Focus two
    final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
    if (!disallowIntercept) {
   
    	// Focus three
    	intercepted = onInterceptTouchEvent(ev);
    	ev.setAction(action
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值