Android touch事件是如何交付的?

Android touch事件是如何交付的?,android,events,Android,Events,我不是在问如何处理触摸事件,而是在幕后发生了什么?如果有几个嵌套的小部件,它们以什么顺序查看事件?开发者对它有控制权吗?理想情况下,我想要一份关于这个主题的文档。从活动的角度: 触摸事件首先传递给Activity.dispatchTouchEvent。在那里你可以先抓住他们 在这里,它们被分派到窗口,在窗口中遍历视图层次结构,以便最后绘制的小部件(在其他小部件之上)有机会首先处理View.onTouchEvent中的touch。若某个视图在onTouchEvent中返回true,则遍历停止,其他

我不是在问如何处理触摸事件,而是在幕后发生了什么?如果有几个嵌套的小部件,它们以什么顺序查看事件?开发者对它有控制权吗?理想情况下,我想要一份关于这个主题的文档。

从活动的角度:

触摸事件首先传递给Activity.dispatchTouchEvent。在那里你可以先抓住他们

在这里,它们被分派到窗口,在窗口中遍历视图层次结构,以便最后绘制的小部件(在其他小部件之上)有机会首先处理View.onTouchEvent中的touch。若某个视图在onTouchEvent中返回true,则遍历停止,其他视图不接收触摸事件

最后,如果没有视图使用触摸,则将其传递到Activity.onTouchEvent


这是你的全部控制权。合乎逻辑的是,你看到的画在其他东西上面的东西,有机会在画在下面的东西之前处理触摸事件。

让我们看一个视觉例子

当触摸事件发生时,首先通知每个人该事件,从活动开始,一直到顶部的视图。然后,每个人都有机会处理事件,从顶部的视图(在触摸区域具有最高Z顺序的视图)开始,一直返回到活动。因此,这项活动是第一次听到它,也是最后一次有机会处理它

如果某个视图组希望立即处理触摸事件(并且不给任何其他人机会),那么它可以在其
onInterceptTouchEvent()中返回
true
。活动没有
onInterceptTouchEvent()
,但您可以重写
dispatchTouchEvent()
来执行相同的操作

如果视图(或视图组)具有
OnTouchListener
,则触摸事件由
OnTouchListener.onTouch()处理。否则它将由
onTouchEvent()
处理。如果对任何触摸事件
onTouchEvent()
返回
true
,则处理在此停止。没有其他人有机会这样做

更详细的解释 上面的图表使事情比实际情况简单一些。例如,在活动和视图组A(根布局)之间还有窗口和DecorView。我在上面遗漏了他们,因为我们通常不必与他们互动。但是,我将在下面列出它们。下面的描述通过源代码跟踪触摸事件。您可以单击链接查看实际的源代码

(更新:源代码已更新,因此行号现在已关闭,但单击链接仍会找到正确的文件。只需搜索方法名称即可。)

  • 将触摸事件通知活动的。触摸事件作为
    运动事件
    传入,其中包含x、y坐标、时间、事件类型和其他信息
  • 触摸事件将发送到车窗的控制面板<代码>窗口
  • 是一个抽象类。实际的实现是
  • 下一个得到通知的是DecorView
    DecorView
    处理状态栏、导航栏、内容区等,它本身是
    ViewGroup
    的一个子类
  • 下一个得到通知(如果我错了请纠正我)的是活动的内容视图。这就是在Android Studio的布局编辑器中创建布局时,以xml格式设置为活动根布局的内容。因此,无论您选择
    相对视图
    线性布局
    、还是
    约束视图
    ,它们都是
    视图组
    的子类。并且ViewGroup将在中收到触摸事件的通知。这是上图中的视图组A
  • ViewGroup
    将包含触摸事件的一部分,包括任何
    ViewGroup
    子项。这是上图中的视图组B
  • 一路上的任何地方,
    ViewGroup
    都可以通过为返回
    true
    来启动通知过程
  • 假设没有
    ViewGroup
    缩短通知,则通知行的自然终点是调用视图的get
  • 现在是时候开始处理这些事件了,然后它第一次有机会处理触摸事件,视图可以处理它
  • 现在,所有的视图组递归地向上移动,有机会以与
    View
    相同的方式处理触摸事件。尽管在上图中我没有指出这一点,
    ViewGroup
    是一个
    View
    子类,所以我描述的关于
    OnTouchListener.onTouch()
    onTouchEvent()
    的所有内容也适用于ViewGroup
  • ,如果没有其他人想要它,该活动还将获得最后一次处理事件的机会
  • 常见问题 我什么时候需要覆盖
    dispatchTouchEvent()

    如果要在任何视图有机会看到触摸事件之前捕捉触摸事件,请在活动中覆盖它。对于视图组(包括根视图),只需覆盖
    onInterceptTouchEvent()
    onTouchEvent()

    我什么时候需要覆盖
    onInterceptTouchEvent()

    如果您只想监视即将到来的触摸通知,您可以在此处执行此操作并返回
    false

    但是,重写此方法的主要目的是让视图组处理某种类型的触摸事件,同时让子对象处理另一种类型的触摸事件。例如,
    ScrollView
    这样做是为了处理滚动,同时让它的子对象处理按钮单击之类的事情。相反,如果子视图不想让其父视图窃取其触摸事件,它可以调用
    requestDisallowTouchIntercept()

    你在做什么
       public boolean dispatchTouchEvent(MotionEvent ev) {
            boolean consume = false;
            if (onInterceptTouchEvent(ev) {
                consume = onTouchEvent(ev);
            } else {
                consume = child.dispatchTouchEvent(ev);
            }
    
            return consume;
        }