系统的学习 Android Touch 事件传递机制

1,398 阅读3分钟

原标题: Mastering the Android Touch System

原文地址: speakerd.s3.amazonaws.com

原文作者: Dave Smith

如何处理 Andriod 触摸事件

所有的 Touch 事件都封装为 MotionEvent 对象,包括触摸的位置,多点触控和事件发生的时间。 事件的基础类型分为 ACTION_DOWN ACTION_UP ACTION_MOVE ACTION_POINTER_DOWN ACTION_POINTER_UP ACTION_CANCEL,并且每个事件都是从 ACTION_DOWN 开始到 ACTION_UP 结束 。对事件的处理包括三类,分别为传递——dispatchTouchEvent() 函数、拦截——onInterceptTouchEvent()函数、消费——onTouchEvent() 函数和 OnTouchListener

事件传递的流程

事件从 Activity.dispatchTouchEvent() 开始传递,如果事件在传递的过程中没有被消费,会从最上层的父视图(ViewGroup) 开始按照从上而下的顺序传递事件直到该事件被消费,在传递的过程中子视图可以随时消耗事件,如果父视图消费了 ACTION_DOWN 事件,之后的其他事件将不会继续传递到子视图处理。任何未消耗的事件都会传递到 ActivityonTouchEvent() 后结束。如果还是没有被消费的话,则会返回到 ActivityonTouchEvent() 函数,可以通过对外的 OnTouchListener 来消费 View/ViewGroup 的任意事件,如果 View.dispatchTouchEvent() 存在的话会将事件交由 View.OnTouchListener.onTouch() 处理,如果事件没有被消费则其自身来负责事件流程。

如果在 ViewGroup.dispatchTouchEvent() 的事件传递过程中,如果父视图的 onInterceptTouchEvent() 中消费了事件则子视图的 onInterceptTouchEvent() 不会在接收到任何的事件,直接由父视图自己进行处理。对于每个子视图会以相反的顺序添加它们,如果在之前没有进行处理,则交由子级的视图进行消费触摸事件。

事件拦截的时候在 onInterceptTouchEvent() 函数返回一个 true,子视图会收到一个 ACTION_CANCEL 事件后则认为该事件已经结束,不在执行下一步的处理,而接下来收到的所有事件则返回 ViewGroup 来进行处理。当然子视图可以调用 requestDisallowTouchIntercept() 来阻碍父视图的 onInterceptTouchEvent() 对当前所滑动的手势进行拦截。

错误的视图案例

有趣的视图案例

处理事件

子类重写 onTouchEvent() 方法,并提供一个 OnTouchListener。使用 ACTION_DOWN 并返回 true 表示消耗该事件即使您对 ACTION_DOWN不大算消耗该事件也请返回 true,对于其他事件,返回 true 会停止事件的进一步处理。

ViewConfiguration 中有用的常量:

  • getScaledTouchSlop():移动距离的事件可能会在其拖动之前就会发生变化
  • getScaledMinimumFlingVelocity():系统认为快速滑动是一种惯性拖拽
  • getScaledPagingTouchSlop():事件池使用一个水平分页手势(i.e. ViewPager)

以上内容是 Mastering the Android Touch System PPT 1-10页的内容总结,文章有些术语及方法释明需要调整校对。剩下的10页会陆续补上。如果有不妥的地方,欢迎大家提出,一起完善。


欢迎关注 Kotlin 中文社区!

中文官网:www.kotlincn.net/

中文官方博客:www.kotliner.cn/

公众号:Kotlin

知乎专栏:Kotlin

CSDN:Kotlin中文社区

掘金:Kotlin中文社区

简书:Kotlin中文社区