我不是在问如何处理触摸事件,而是在幕后发生了什么?如果有几个嵌套的小部件,他们看到的事件是什么顺序?开发人员是否可以控制它?理想情况下,我想要一个关于这个主题的文件。
答案 0 :(得分:49)
让我们来看一个视觉示例。
当触摸事件发生时,首先会向每个人通知该事件,从活动开始并一直到顶部的视图。然后每个人都有机会处理事件,从顶部视图开始(视图在触摸区域中具有最高Z顺序)并一直返回到活动。因此,活动是第一个听到它并且最后一个有机会处理它。
如果某个ViewGroup想要立即处理触摸事件(而不是让其他任何人有机会),那么它只能在其true
中返回onInterceptTouchEvent()
。活动没有onInterceptTouchEvent()
,但您可以覆盖dispatchTouchEvent()
来执行相同操作。
如果视图(或ViewGroup)具有OnTouchListener
,则触摸事件由OnTouchListener.onTouch()
处理。否则由onTouchEvent()
处理。如果onTouchEvent()
针对任何触摸事件返回true
,那么处理就会停止。没有其他人可以获得机会。
上图让事情变得比实际更简单。例如,在Activity和ViewGroup A(根布局)之间还有Window和DecorView。我把它们排除在上面,因为我们通常不必与它们互动。但是,我会将它们包含在下面。以下描述遵循通过源代码的触摸事件。您可以单击链接以查看实际的源代码。
(更新:源代码已更新,因此行号现已关闭,但点击链接仍会将您转到正确的文件。只需搜索方法名称。)
dispatchTouchEvent()
会收到触摸事件的通知。触摸事件以MotionEvent
传递,其中包含x,y坐标,时间,事件类型和其他信息。superDispatchTouchEvent()
。 Window
是一个抽象类。实际实施是PhoneWindow
。superDispatchTouchEvent()
。 DecorView
处理状态栏,导航栏,内容区域等It is actually just a FrameLayout
subclass,它本身就是ViewGroup
的子类。RelativeLayout
,LinearLayout
还是ConstraintLayout
,它们都是ViewGroup
的子类。并且ViewGroup会在dispatchTouchEvent()
中收到有关触摸事件的通知。这是我上图中的 ViewGroup A 。 ViewGroup
notify any children会有触摸事件,包括任何ViewGroup
个孩子。这是我上图中的 ViewGroup B 。ViewGroup
可以short-circuit通知{* 3}} onInterceptTouchEvent()
。true
将通知缩短,通知行的自然结束就是查看了dispatchTouchEvent()
的If there is an OnTouchListener
。onTouch()
,然后第一次有Otherwise处理触摸事件的机会。 onTouchEvent()
,View Finally可以处理它。 ViewGroup
的方式处理触摸事件。虽然,我在上图中没有说明这一点,但View
是ViewGroup
子类,因此我所描述的关于View
和OnTouchListener.onTouch()
的所有内容也适用于ViewGroups onTouchEvent()
,如果没有其他人想要,活动也会获得使用here处理该活动的最后机会。 我什么时候需要覆盖onTouchEvent()
?
如果您想在任何视图获得机会之前捕获触摸事件,请在活动中覆盖它。对于ViewGroup(包括根视图),只需覆盖dispatchTouchEvent()
和onInterceptTouchEvent()
。
我什么时候需要覆盖onTouchEvent()
?
如果您只想监视即将发出的触摸通知,可以在此处执行并返回onInterceptTouchEvent()
。
但是,重写此方法的主要目的是让ViewGroup处理某种类型的触摸事件,同时让子处理另一种类型。例如,false
执行此操作以处理滚动,同时让其子项处理类似按钮单击的操作。相反,如果子视图不想让其父级窃取其触摸事件,则可以调用ScrollView
。
有什么触摸事件类型?
主要是
requestDisallowTouchIntercept()
- 这是触摸事件的开始。如果您要处理触摸事件,则应始终在ACTION_DOWN
中为true
事件返回ACTION_DOWN
。否则,您将无法再获得任何活动。onTouchEvent
- 当您在屏幕上移动手指时,此事件会不断触发。ACTION_MOVE
- 这是触摸事件的最后一个事件。亚军是ACTION_UP
。如果树上的ViewGroup决定拦截触摸事件,则会调用此方法。
您可以查看其他类型的MotionEvents Part 1。由于Android是多点触控的,当其他手指("指针")触摸屏幕时,也会触发事件。
答案 1 :(得分:23)
从活动角度来看:
触摸事件首先传递给Activity.dispatchTouchEvent。这是你可以先抓住它们的地方。
在这里,他们将被调度到Window,在那里他们遍历View层次结构,其顺序是最后绘制的Widgets(在其他小部件之上)有机会首先在View.onTouchEvent中处理触摸。如果某些View在onTouchEvent中返回true,则遍历停止,而其他视图不会收到触摸事件。
最后,如果没有View消耗触摸,它将被传递给Activity.onTouchEvent。
这就是你的全部控制权。而且你所看到的东西在其他东西之上绘制是合乎逻辑的,有机会在它下面绘制的东西之前处理触摸事件。
答案 2 :(得分:1)
根据Suragch的回答,
伪代码:
public boolean dispatchTouchEvent(MotionEvent ev) {
boolean consume = false;
if (onInterceptTouchEvent(ev) {
consume = onTouchEvent(ev);
} else {
consume = child.dispatchTouchEvent(ev);
}
return consume;
}
REF:机器人开发艺术探索
答案 3 :(得分:0)
我准备了一个高级图,该图应说明一个简单的流程。 请随时comment and edit it。