Android触摸事件是如何发布的?

DJC*_*rth 32 events android

我不是在问如何处理触摸事件,而是在幕后发生了什么?如果有几个嵌套的小部件,他们看到的事件是什么顺序?开发人员是否可以控制它?理想情况下,我想要一个关于这个主题的文件.

Sur*_*gch 65

我们来看一个视觉示例.

在此输入图像描述

当触摸事件发生时,首先向每个人通知事件,从活动开始并一直到顶部的视图.然后每个人都有机会处理事件,从顶部视图开始,一直回到活动.因此,活动是第一个听到它并且最后有机会处理它.

在此输入图像描述

如果某个ViewGroup想要立即处理触摸事件(并且没有让其他任何人有机会),那么它就可以返回trueonInterceptTouchEvent().活动没有,onInterceptTouchEvent()但您可以覆盖dispatchTouchEvent()以执行相同的操作.

如果View(或ViewGroup)具有OnTouchListener,则触摸事件由处理OnTouchListener.onTouch().否则它由处理onTouchEvent().如果任何触摸事件onTouchEvent()返回true,则处理停止.没有其他人有机会获得它.

更详细的解释

上图使事情比实际更简单.例如,在Activity和ViewGroup A(根布局)之间还有Window和DecorView.我把它们排除在上面,因为我们通常不必与它们互动.但是,我会将它们包含在下面.以下描述遵循通过源代码的触摸事件.您可以单击链接以查看实际的源代码.

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

  1. 活动dispatchTouchEvent()被通知触摸事件.触摸事件作为a传入MotionEvent,其中包含x,y坐标,时间,事件类型和其他信息.
  2. 触摸事件被发送到Window的superDispatchTouchEvent().Window是一个抽象类.实际的实现是PhoneWindow.
  3. 获取通知的下一个是DecorView superDispatchTouchEvent().DecorView它处理状态栏,导航栏,内容区等.它实际上只是一个FrameLayout子类,它本身就是一个子类ViewGroup.
  4. 下一个获取通知(如果我错了,请更正我)是您活动的内容视图.这是您在Android Studio的布局编辑器中创建布局时在xml中设置为活动的根布局的内容.因此,无论您选择a RelativeLayout,a LinearLayout还是a ConstraintLayout,它们都是子类ViewGroup.并且ViewGroup会收到有关触摸事件的通知dispatchTouchEvent().这是上图中的ViewGroup A.
  5. ViewGroup通知任何孩子有触摸事件,包括任何ViewGroup儿童.这是我上图中的ViewGroup B.
  6. 在此过程中的任何地方,ViewGroup都可以通过返回来短路通知过程.trueonInterceptTouchEvent()
  7. 假设没有ViewGroup剪切通知短,通知行的自然结束是View dispatchTouchEvent()的调用.
  8. 现在是时候开始处理事件了.如果有OnTouchListener,那么它第一次有机会处理触摸事件onTouch().否则,View onTouchEvent()会处理它.
  9. 现在所有ViewGroups递归上线都有机会以同样的方式处理触摸事件View.虽然,我没有表明这上面的图中,一个ViewGroupView子类,所以一切我已描述OnTouchListener.onTouch()onTouchEvent()也适用于ViewGroups.
  10. 最后,如果没有其他人想要它,Activity也会获得最后一次处理事件的机会onTouchEvent().

常问问题

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

如果要在任何视图有机会之前捕获触摸事件,请在活动中覆盖它.对于ViewGroup(包括根视图),然后只需覆盖onInterceptTouchEvent()onTouchEvent().

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

如果您只想窥探即将进入的触摸通知,您可以在此处进行并返回false.

但是,重写此方法的主要目的是让ViewGroup处理特定类型的触摸事件,同时让子处理另一种类型.例如,a ScrollView执行此操作以处理滚动,同时让其子项处理类似Button按钮的操作.相反,如果子视图不想让其父级窃取其触摸事件,则可以调用requestDisallowTouchIntercept().

什么是触摸事件类型?

主要是

  • ACTION_DOWN - 这是触摸事件的开始.你应该总是返回trueACTION_DOWN事件onTouchEvent,如果你要处理的触摸事件.否则,您将无法再获得任何活动.
  • ACTION_MOVE - 当您在屏幕上移动手指时,此事件会不断触发.
  • ACTION_UP - 这是触摸事件的最后一个事件.

亚军是ACTION_CANCEL.如果树上的ViewGroup决定拦截触摸事件,则会调用此方法.

您可以在此处查看其他类型的MotionEvent .由于Android是多点触控的,因此当其他手指("指针")触摸屏幕时也会触发事件.

进一步研究


Poi*_*ull 24

从活动角度来看:

Touch事件首先传递给Activity.dispatchTouchEvent.这是你可以先抓住它们的地方.

在这里,他们被调度到Window,在那里他们遍历View层次结构,其顺序是最后绘制的Widgets(在其他小部件之上)有机会首先在View.onTouchEvent中处理触摸.如果某些View在onTouchEvent中返回true,则遍历停止并且其他视图不会接收触摸事件.

最后,如果没有View消耗触摸,它将被传递给Activity.onTouchEvent.

这完全是你的控制.而且你所看到的东西在其他东西之上绘制是合乎逻辑的,有机会在它下面绘制的东西之前处理触摸事件.


yoA*_*ex5 5

我已经准备了一个高级图来说明一个简单的流程。

在此处输入图片说明

  • dispatchTouchEvent()- Activity, ViewGroup,View
  • onInterceptTouchEvent() —— ViewGroup
  • onTouch()- ViewGroupView。使用setOnTouchListener()
  • onTouchEvent()- Activity, ViewGroup,View

[iOS onTouch]