介绍Android Touch事件的传递机制。
不少朋友私信问到这个问题,那就推荐一篇我看到的对传递机制介绍最清楚的国外文章吧。本文略作翻译。
1、基础知识
(1) 所有Touch事件都被封装成了MotionEvent对象,包括Touch的位置、时间、历史记录以及第几个手指(多指触摸)等。
(2) 事件类型分为ACTION_DOWN, ACTION_UP, ACTION_MOVE, ACTION_POINTER_DOWN, ACTION_POINTER_UP, ACTION_CANCEL,每个事件都是以ACTION_DOWN开始ACTION_UP结束。
(3) 对事件的处理包括三类,分别为传递——dispatchTouchEvent()函数、拦截——onInterceptTouchEvent()函数、消费——onTouchEvent()函数和OnTouchListener
2、传递流程
(1) 事件从Activity.dispatchTouchEvent()开始传递,只要没有被停止或拦截,从最上层的View(ViewGroup)开始一直往下(子View)传递。子View可以通过onTouchEvent()对事件进行处理。
(2) 事件由父View(ViewGroup)传递给子View,ViewGroup可以通过onInterceptTouchEvent()对事件做拦截,停止其往下传递。
(3) 如果事件从上往下传递过程中一直没有被停止,且最底层子View没有消费事件,事件会反向往上传递,这时父View(ViewGroup)可以进行消费,如果还是没有被消费的话,最后会到Activity的onTouchEvent()函数。
(4) 如果View没有对ACTION_DOWN进行消费,之后的其他事件不会传递过来。
(5) OnTouchListener优先于onTouchEvent()对事件进行消费。
上面的消费即表示相应函数返回值为true。
更多请直接阅读PDF英文原文:Mastering the Android Touch System,示例代码:Demo@Github。有什么问题可以这里留言。
附上两张原文中流程图
(1) View不处理事件流程图
(2) View处理事件流程图
好文,终于找到原因了.
这么多篇关于 view touch 事件分发的文章里,虽然最短小,却是解释得最正确 (是的,最正确) 和最清晰的一篇。好多文章说 onTouchEvent() 返回 false,就接着把事件分发给子控件,这是错误的。如果执行到 onTouchEvent() 了,那就说明事件要开始往上层 (ParentView) 回溯了,压根不会再往下层 (ChildView) 分发了。
Pingback: PhotoView 源码解析 | 技术联盟
Pingback: PhotoView源码解析 | 风语的博客
http://v.youku.com/v_show/id_XODQ1MjI2MDQ0.html 关于楼主说的这个教程,我已经上传到优酷了,而且做了中英字幕,大家可以去看看 顺便可以微博粉我:Ocean-藏心
太棒了这视频,你的翻译也很不错,谢谢
https://github.com/oceancx/android-subtitles 字幕文件下载 以及我的其他字幕
触摸事件分发机制研究了好久,一些复杂的布局里有时候需要路由事件的传递路径,搞完很快又说不清这个机制了。感觉还是总结出一些东西好,结论容易记住点。隐约记得,Clickable的控件是自动消费事件的,UnClickable是不消费……
这个 pdf 简单易懂,花十分钟看看就行
那个PDF?
哦 我知道了 好的 谢谢 没看仔细
第四点,如果View没有对ACTION_DOWN进行消息… 这里应该是“消费”
已修正,多谢
viewpager中的某个页面是webview,加载了一个页面含有js控制的动态滚动图,该滚动图支持手势。此时问题出现了,因为在viewpager中,所以只响应viewpager的手势滚动,而webview中的手势效果不响应,怎么解决啊?trinea
看完上面的介绍,你就知道怎么禁用掉viewPager的事件处理了
禁用掉viewpager的事件后,webview的事件好使,但viewpager的事件无效了啊。我想问这样可以搞吗?viewpager把事件传递给webview,webview如果消费不了,再交给viewpager消费。但是,无论webview的ontouch事件返回true或者false,viewpager都不再处理消费事件。
你肯定没看上面的介绍…..默认就是”viewpager把事件传递给webview,webview如果消费不了,再交给viewpager消费”
是不是可以考虑在ViewPager的onInterceptTouchEvent中进行拦截处理
public boolean onInterceptTouchEvent(MotionEvent arg0) { // TODO Auto-generated method stub if (getCurrentItem() == 1 && arg0.getY() < childVPHeight) { Log.i(“zc”,”MyViewpage..onInterceptTouchEvent..into webview..”); return false; } return super.onInterceptTouchEvent(arg0); }注:getCurrentItem是包含webView的那个Fragment,childVpHeight是webview的高度
哈哈,换个友链吧
给我自己打个广告: http://www.fookwood.com/archives/806
哈哈,换个友链吧