05/05
2014

Android Touch事件传递机制

介绍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不处理事件流程图

view-ignore-touch-event-example

view-ignore-touch-event-example

 

(2) View处理事件流程图

view-process-touch-event-example

view-process-touch-event-example

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

24 thoughts on “Android Touch事件传递机制

  1. 这么多篇关于 view touch 事件分发的文章里,虽然最短小,却是解释得最正确 (是的,最正确) 和最清晰的一篇。好多文章说 onTouchEvent() 返回 false,就接着把事件分发给子控件,这是错误的。如果执行到 onTouchEvent() 了,那就说明事件要开始往上层 (ParentView) 回溯了,压根不会再往下层 (ChildView) 分发了。

  2. Pingback: PhotoView 源码解析 | 技术联盟

  3. Pingback: PhotoView源码解析 | 风语的博客

  4. 触摸事件分发机制研究了好久,一些复杂的布局里有时候需要路由事件的传递路径,搞完很快又说不清这个机制了。感觉还是总结出一些东西好,结论容易记住点。隐约记得,Clickable的控件是自动消费事件的,UnClickable是不消费……

  5. viewpager中的某个页面是webview,加载了一个页面含有js控制的动态滚动图,该滚动图支持手势。此时问题出现了,因为在viewpager中,所以只响应viewpager的手势滚动,而webview中的手势效果不响应,怎么解决啊?trinea

      • 禁用掉viewpager的事件后,webview的事件好使,但viewpager的事件无效了啊。我想问这样可以搞吗?viewpager把事件传递给webview,webview如果消费不了,再交给viewpager消费。但是,无论webview的ontouch事件返回true或者false,viewpager都不再处理消费事件。

    • 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的高度