大厂Android高频问题:Android-触摸事件如何传递?

本文深入探讨了Android开发面试中常见的触摸事件传递机制,解析了从ACTION_DOWN到ACTION_UP的过程,涉及Activity、View和ViewGroup的角色,以及如何处理和消费触摸事件。通过对涉及的类和方法的分析,阐述了事件传递的详细步骤和核心逻辑。
摘要由CSDN通过智能技术生成

前言

触摸传递机制可以说是Android开发面试高频的一道问题,但总有小伙伴在回答这道问题总不能让面试满意, 本篇就搞清楚面试官问你对触摸传递机制原理时,他最想听到的和其实想问的应该是哪些?下文中,我们将简单剖析一下 Android 的触摸传递机制。

涉及到的类和方法

总的来说,触摸传递过程是由上至下的。一个典型的触摸事件,从 Activity 开始,经过根视图,再经过层层 ViewGroup,最终传递到某一个 ViewViewGroup 上,进行处理。主要涉及到的类自然包括 ActivityViewGroup 以及 View 了。

首先,在 ActivityView 中,都定义了下面两个方法 (虽然在这两个类中,这两个方法的方法名,参数列表和返回值类型完全一样,但 Activity 并不是 View 的子类,下面的两个方法在 ActivityView 中被单独定义)。

// 尝试将触摸事件交给自己的子视图 (如果有的话) 处理: 调用子视图的 dispatchTouchEvent()
// 或者自己处理: 调用自己的 onTouchEvent() 或 OnTouchListener.onTouch()
// 无论是自己的子视图,还是自己,完成了事件处理,都返回 true
public boolean dispatchTouchEvent(MotionEvent ev)
// 尝试自己处理触摸事件. 如果完成处理 (不需要再交给其他 View 处理), 则返回 true
public boolean onTouchEvent(MotionEvent event)

由于 ViewGroupView 的子类,所以自然 ViewGroup 中也存在这两个方法。在 ViewGroup 中还单独定义了方法

// 如果事件需要在该 ViewGroup 截断 (自己处理该事件, 不再传递给其子视图), 则返回 true
public boolean onInterceptTouchEvent(MotionEvent ev)

以上3个方法,通常只有在我们需要自定义 View 时,才需要 Override。对于现成的 View,我们可以通过 View (也包括 ViewGroup) 的 setOnTouchListener() 方法,添加触摸事件监听器来监听触摸事件,

someView.setOnTouchListener(new View.OnTouchListener() {
   
    @Override
    public boolean onTouch(View v, MotionEvent event) {
   
        // 尝试自己处理触摸事件, 完成处理 (不需要其他 View 再处理), 则返回 true
        // ...
    }
});

同样可以起到和 onTouchEvent() 类似的效果。两者有什么区别,包括前面的几个方法的具体作用,会在下文中慢慢解释。

在这之前,我们应当注意到,

  • 它们都具有一个 MotionEvent 类型的参数,里面包含有触摸事件的详细信息 (包含事件的类型,手指按下还是松开,以及触摸的具体坐标位置等),本文涉及的大部分方法都有这个参数,后面就不再重复了。限于篇幅,这里对该类的使用就不详细介绍了。对 MotionEvent 有疑问可以参考官方文档中对 MotionEvent 的描述。
  • 它们都返回一个 boolean 值,通过返回 true,来声明触摸事件在自己这里已经完成,或者说“消费”掉了。例如,文章开头的例子中, ListView 的某一项 ( item ) 对应的视图 View 监听到一个触摸事件,发现是左右滑动的手势,该 View 就会选择将这个事件“消费”掉,这样其父视图 ListViewPageViewer 以及 Activity 就不会重复处理这一事件。

传递机制详解

先分别看看上面的4个方法的具体作用,以及 boolean 返回值的意义。

Activity

先看第一个方法 dispatchTouchEvent(),该方法是整个触摸传递机制的核心。一般地,父视图 ( parent view ) 通过调用子视图 ( child view ) 的 dispatchTouchEvent() 方法完成触摸事件的向下传递。

焦点所在 ActivitydispatchTouchEvent() 方法,是整个触摸事件的“入口”。该方法首先,无条件地,不可被截断地 (除非你 Override ActivitydispatchTouchEvent() 方法),将事件交给它的下属处理,即调用该 Activity 的根视图的 dispatchTouchEvent() 方法。如果它的下属没有完成该事件的处理 (调用结果返回 false),则尝试自己处理,即调用 Activity 自己的 onTouchEvent() 方法。如果仍然不能完成处理 (调用结果返回 false),则可以认为该事件的处理宣告失败,整个方法返回 false (完成了处理则返回 true)。

注意,如果第一次调用 (即调用下属视图的 dispatchTouchEvent() 方法),返回了 true,表示下属已经完成了对事件的处理工作,此时不会再调用 Activity 自己的 onTouchEvent() 方法。

因为 Activity 没有父视图,自身不能设置触摸事件的监听器 OnTouchListener,也没有 onInterceptTouchEvent() 方法,情况相对简单,就不给大家 show 源代码了。

没有子视图的 View

下面我们再看一下另一个比较简单的情况,即没有子视图的 View (如果套用二叉树的概念,Activity 是树根&

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值