彻底掌握Android touch事件的分发机制


主要参考文献:任玉刚《Android开发艺术探索》

1. 基本介绍

1.1 MotionEvent分类
事件 简介
ACTION_DOWN 手指初次接触到屏幕时触发
ACTION_MOVE 手指在屏幕上滑动时触发、会多次触发
ACTION_UP 手指离开屏幕时触发
ACTION_CANECL 事件被上层拦截时触发
1.2 控件的事件分发、拦截、消费

√表示有该方法,×表示没有该方法

类型 相关方法 Activity ViewGroup View
事件分发 dispatchTouchEvent
事件拦截 onInterceptTouchEvent × ×
事件消费 OnTouchEvent ×

整个 View 之间的事件分发,实质上就是一个大的递归函数,而这个递归函数就是 dispatchTouchEvent 方法。在这个递归的过程中会适时调用 onInterceptTouchEvent 来拦截事件,或者调用 onTouchEvent 方法来处理事件。用下面一段伪代码帮助我们更好的理解他们之间的调用关系:

public boolean dispatchTouchEvent(MotionEvent ev) {
    
    boolean consume = false;
    //ViewGroup是否拦截,若拦截则交给自己的onTouchEvent处理
    if (onInterceptTouchEvent(ev)) {
    
        consume = onTouchEvent(ev); 
    } else {
   //不拦截,则继续向子控件进行分发
        consume = child.dispatchTouchEvent(ev); 
    }
    return consume; 
}
1.3 大致流程图

在这里插入图片描述

当一个点击事件产生以后,它的传递或者说分发过程遵循如下顺序:Activity—>Window—>DecorView—>ViewGroup—>View, 如果一个View的onTouchEvent返回false,表示它没有消费事件,那么

2. Activity对点击事件分发过程

点击事件用MotionEvent来表示,当一个点击操作发生时,事件最先传递给当前 Activity,由Activity的dispatchTouchEvent来进行事件派发,具体的工作是由Activity内部 的Window来完成的。Window会将事件传递给decor view,decor view一般就是当前界面的底层容器(即setContentView所设置的View的父容器),通过 Activity.getWindow.getDecorView()可以获得。我们先从Activity的dispatchTouchEvent开始 分析。

Activity#dispatchTouchEvent ()

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

现在分析上面的代码。首先事件开始交给Activity所附属的Window进行分发,如果返 回true,整个事件循环就结束了,返回false意味着事件没人处理,所有View的 onTouchEvent都返回了false,那么Activity的onTouchEvent就会被调用。 接下来看Window是如何将事件传递给ViewGroup的。通过源码我们知道,Window是 个抽象类,而Window的superDispatchTouchEvent方法也是个抽象方法,因此我们必须找到Window的实现类才行。而我们知道由于Window的唯一实现是PhoneWindow,因此接下来看一下PhoneWindow是如何处 理点击事件的,如下所示。

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

到这里逻辑就很清晰了,PhoneWindow将事件直接传递给了DecorView,这个 DecorView是什么呢?请看下面:

public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
    
    // This is the top-level view of the window,containing the window decor. private DecorView mDecor; 
    @Override public final View getDecorView() {
    
    if (mDecor == null) {
    
        installDecor(); 
    
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值