我不是在问如何处理触摸事件,而是幕后发生了什么?如果有几个嵌套的小部件,他们看到事件的顺序是什么?开发者是否有任何控制权?理想情况下,我想要一个关于这个问题的文件。Android touch事件是如何传递的?
回答
活动观点:
触摸事件首先被传递给Activity.dispatchTouchEvent。这是你第一次接触到它的地方。
在这里,它们被调度到窗口,在窗口中它们遍历View层次结构,以便最后绘制的窗口小部件(在其他窗口小部件之上)有机会先处理View.onTouchEvent中的接触。如果某些View在onTouchEvent中返回true,则遍历停止和其他视图不会收到触摸事件。
最后,如果没有View消耗touch,它会传递给Activity.onTouchEvent。
这就是你的全部控制。从逻辑上看,你在其他东西上绘制的东西,有机会在绘制它之前的东西之前处理触摸事件。
让我们来看看一个视觉例子。
当触摸事件发生时,起初大家被告知事件的开始,活动中去,一路到顶部的视图。然后,每个人都有机会处理该事件,从顶层视图开始,一直回到活动。所以活动是第一个听到它,最后有机会处理它。
如果活动或某些ViewGroup中要处理的触摸事件马上(而不是给别人下了线它的机会),那么它可以只在其onInterceptTouchEvent()
返回true
。
如果视图(或视图组)具有OnTouchListener
,则触摸事件由OnTouchListener.onTouch()
处理。否则它由onTouchEvent()
处理。如果onTouchEvent()
针对任何触摸事件返回true
,则处理在那里停止。没有其他人能够得到机会。
更详细的解释
上图,使事情变得更加简单比实际。例如,在Activity和ViewGroup A(根布局)之间还有Window和DecorView。我将它们排除在上面是因为我们通常不需要与它们交互。不过,我会在下面包含它们。下面的描述通过源代码跟随触摸事件。您可以点击链接查看实际的源代码。
- 活动的
dispatchTouchEvent()
被通知触摸事件。触摸事件作为MotionEvent
传入,其中包含x,y坐标,时间,事件类型和其他信息。 - 触摸事件发送到窗口的
superDispatchTouchEvent()
。Window
是一个抽象类。实际执行是PhoneWindow
。 - 接下来要获得通知的是DecorView的
superDispatchTouchEvent()
。DecorView
是处理状态栏,导航栏,内容区域等的内容。It is actually just aFrameLayout
subclass,它本身是ViewGroup
的子类。 - 下一个得到通知(纠正我,如果我错了)是您的活动的内容视图。当您在Android Studio的布局编辑器中创建布局时,这就是您在xml中设置的活动的根布局。因此,无论您选择
RelativeLayout
,LinearLayout
还是ConstraintLayout
,它们都是ViewGroup
的子类。并且ViewGroup在dispatchTouchEvent()
中得到触摸事件的通知。这是我上图中的ViewGroup A。 ViewGroup
将notify any children它有触摸事件,包括任何ViewGroup
孩子。在我上面的图中,这是ViewGroup B。- 随时随地都可以,
ViewGroup
可以short-circuit通知处理通过返回true
为onInterceptTouchEvent()
。 - 假设没有
ViewGroup
将通知缩短,则通知行的自然结束时是查看的dispatchTouchEvent()
get被调用。 - 现在是时候开始处理事件了。 If there is an
OnTouchListener
,那么它将以第一个机会处理触摸事件onTouch()
。 Otherwise,视图的onTouchEvent()
得到处理它。 - 现在所有ViewGroups递归上线都有机会像
View
一样处理触摸事件。虽然我没有在上图中指出这一点,但ViewGroup
是View
的子类,所以我所描述的有关OnTouchListener.onTouch()
和onTouchEvent()
的所有内容也适用于ViewGroups。 - Finally,如果没有其他人需要它,活动也有最后机会处理
onTouchEvent()
事件。
FAQ
当我会永远需要重写dispatchTouchEvent()
?
也许你不需要,除非你需要做一些额外的路由,默认情况下不会发生。要监控触摸事件通知,您可以改写onInterceptTouchEvent()
。
我什么时候需要重写onInterceptTouchEvent()
?
如果您只是想监视正在进入的触摸通知,您可以在此处执行此操作并返回false
。
但是,覆盖此方法的主要目的是让ViewGroup处理特定类型的触摸事件,同时让子处理另一种类型。例如,一个ScrollView
这样做来处理滚动,同时让它的孩子处理像点击按钮。相反,如果子视图不想让父母窃取其触摸事件,则可以拨打requestDisallowTouchIntercept()
。
什么是触摸事件类型?
主要的有
ACTION_DOWN
- 这是一个触摸事件的开始。如果要处理触摸事件,则应始终在onTouchEvent
中返回true
用于ACTION_DOWN
事件。否则,您将无法再获得更多活动。ACTION_MOVE
- 当您在屏幕上移动手指时,此事件不断触发。ACTION_UP
- 这是触摸事件的最后一个事件。
亚军是ACTION_CANCEL
。如果树上的ViewGroup决定拦截触摸事件,则会被调用。
您可以查看其他种类的MotionEvents here。由于Android是多点触控,当其他手指(“指针”)触摸屏幕时,事件也会被触发。
进一步研究
- 的Android的onTouchEvent Part 1,Part 2,并Part 3(YouTube视频 - 一些下面的链接很好的总结)
- Mastering the Android Touch System(彻底视频由谷歌开发者)
- Android UI Internal : Pipeline of View's Touch Event Handling
- Managing Touch Events in a ViewGroup(Android文档)
- Input Events(Android d OCS)
- Gestures and Touch Events
- 1. 如何确定我的UIButton事件是否是Touch Down?
- 2. android将onClick事件传递给孩子
- 3. iOS touch事件
- 4. 如何更改android touch事件的采样率?
- 5. 如何将X11事件传递给QDialog
- 6. 如何将事件传递给方法?
- 7. 如何传递事件接口?
- 8. 使用addEventListener时事件参数是如何传递的?
- 9. 如何在scrollview下做imageView touch事件?
- 10. 如何让CCSprite处理Touch事件?
- 11. 如何将事件传递给另一个事件
- 12. Cocos2d iphone touch事件
- 13. 在.NET中传递事件
- 14. 传递事件到功能?
- 15. UIPresentationController传递触摸事件
- 16. 传递值和事件
- 17. C#冒泡/传递事件
- 18. 将事件传递给UIScrollView
- 19. Console.ReadLine()传递给C#事件
- 20. 传递ID点击事件
- 21. 传递触摸事件
- 22. 强制流事件传递
- 23. 如何使用aasm将传递给事件的参数传递给错误块?
- 24. 如何将应用程序中的事件传递给Android中的活动?
- 25. 如何将事件传递给父视图,传递触发事件的子视图?
- 26. 传递事件到jQuery的插件
- 27. 如何在Android上将视图的onClick事件传递给其父项?
- 28. 如何将事件传递到绑定事件的功能 - jQuery的手机
- 29. 如何将onListItemClick事件中的字符串传递给android中同一活动的onButtonClick事件?
- 30. 如何在jQuery中传递多个事件句柄并传递数据
你有什么样的描述这个文件? – DJClayworth
关于调度:我可以阅读源代码和功能评论。 关于查看遍历的顺序 - 我已经在一些文档中阅读过,当然在developer.android.com上,但是不能准确地告诉现在哪个。 –
无论如何,好开始:http://developer.android.com/guide/topics/ui/ui-events.html –