Touch模拟实例

Touch事件传递

Posted by Mio4kon on 2015-09-22

Touch模拟实例

关于Touch事件的几个模拟示例.如果对分发机制不是很了解的,又没有太多时间模拟实验的,可以参考.

原流程

例子有3个控件:

GrandparentView extends ViewGroup (粉色)
ParentView extends ViewGroup (蓝色)
ChildView extends View(棕色)

其中GrandparentView是ParentView的父布局,ParentView是ChildView的父布局.

模拟1:仅仅点击GrandparentView区域

  1. GrandparentView dispatchTouchEvent ACTION_DOWN
  2. GrandparentView onInterceptTouchEvent ACTION_DOWN
  3. GrandparentView onTouchEvent ACTION_DOWN

模拟2:点击ParentView部分区域

  1. GrandparentView dispatchTouchEvent ACTION_DOWN
  2. GrandparentView onInterceptTouchEvent ACTION_DOWN
  3. ParentView dispatchTouchEvent ACTION_DOWN
  4. ParentView onInterceptTouchEvent ACTION_DOWN
  5. ParentView onTouchEvent ACTION_DOWN
  6. GrandparentView onTouchEvent ACTION_DOWN

模拟3:点击ChildView部分区域

  1. GrandparentView dispatchTouchEvent ACTION_DOWN
  2. GrandparentView onInterceptTouchEvent ACTION_DOWN
  3. ParentView dispatchTouchEvent ACTION_DOWN
  4. ParentView onInterceptTouchEvent ACTION_DOWN
  5. ChildView dispatchTouchEvent ACTION_DOWN
  6. ChildView onTouchEvent ACTION_DOWN
  7. ParentView onTouchEvent ACTION_DOWN
  8. GrandparentView onTouchEvent ACTION_DOWN

以上都是在原基础上打的Log,即不修改任何返回值的情况下的输出顺序.

可以发现:
ViewGroup执行顺序从dispatchTouchEventonInterceptTouchEvent,然后询问子ViewGroupdispatchTouchEventonInterceptTouchEvent,再然后从子View
dispatchTouchEventonTouchEvent,由于子View没有onInterceptTouchEvent.所以如果子View不消费事件,就反向到父布局的onTouchEvent.

问题:明明是点击事件,为什么没有消费UP事件?
实际上,事件传递在View没有消费的时候,最终会传递给Activity的onTouchEvent.
所以实际上是如果按照模拟1(其他同理)来说应该是:

  1. GrandparentView dispatchTouchEvent ACTION_DOWN
  2. GrandparentView onInterceptTouchEvent ACTION_DOWN
  3. GrandparentView onTouchEvent ACTION_DOWN
  4. Activity onTouchEvent ACTION_DOWN
  5. Activity onTouchEvent ACTION_UP

onTouchEvent 相关

用于处理事件.可以消费事件.

模拟4:ChildViewonTouchEvent返回true,点击ChildView部分区域

此时应该是分发到最终View–ChildView,在反向询问是否onTouchEvent消费的时候直接由ChildView消费.即:

注:点击事件是分发了down 和 up 两个事件.

  1. GrandparentView dispatchTouchEvent ACTION_DOWN
  2. GrandparentView onInterceptTouchEvent ACTION_DOWN
  3. ParentView dispatchTouchEvent ACTION_DOWN
  4. ParentView onInterceptTouchEvent ACTION_DOWN
  5. ChildView dispatchTouchEvent ACTION_DOWN
  6. ChildView onTouchEvent ACTION_DOWN
  7. GrandparentView dispatchTouchEvent ACTION_UP
  8. GrandparentView onInterceptTouchEvent ACTION_UP
  9. ParentView dispatchTouchEvent ACTION_UP
  10. ParentView onInterceptTouchEvent ACTION_UP
  11. ChildView dispatchTouchEvent ACTION_UP
  12. ChildView onTouchEvent ACTION_UP

模拟5:GrandparentViewonTouchEvent返回true,点击ChildView部分区域

这个实验几乎与模拟4一样.猜想是:
从父类分发,直到ChildView,然后反向轮训到GrandparentViewonTouchEvent方法消费.
事实的确如此,但有一个有趣的现象:
ACTION_DOWN 的确如此,ACTION_UP却在GrandparentView分发后立刻执行了onTouchEvent
下面是完整的流程.

  1. GrandparentView dispatchTouchEvent ACTION_DOWN
  2. GrandparentView onInterceptTouchEvent ACTION_DOWN
  3. ParentView dispatchTouchEvent ACTION_DOWN
  4. ParentView onInterceptTouchEvent ACTION_DOWN
  5. ChildView dispatchTouchEvent ACTION_DOWN
  6. ChildView onTouchEvent ACTION_DOWN
  7. ParentView onTouchEvent ACTION_DOWN
  8. GrandparentView onTouchEvent ACTION_DOWN
  9. GrandparentView dispatchTouchEvent ACTION_UP <—到这里还是挺正常的
  10. GrandparentView onTouchEvent ACTION_UP

模拟4 是在最底层的View消费事件的.两个事件都会从头传递一遍.
模拟5 不在最底层消费事件,第一次会从头传递到底层然后反向轮训直到消费.第二次从上层传递,到当前直接进入到onTouch消费.而不会再传到底层.

当某一层的View消费了事件,那么以后的事件都不会再向下传递(以后的事件,即没有离开区域.比如说一次点击事件.比如说点击移动事件等)

dispatchTouchEvent

用于分发事件.也可以消费事件.

模拟6:ParentViewdispatchTouchEvent返回为true,点击ChildView部分

  1. GrandparentView dispatchTouchEvent ACTION_DOWN
  2. GrandparentView onInterceptTouchEvent ACTION_DOWN
  3. ParentView dispatchTouchEvent ACTION_DOWN

ACTION_UP同理.可见dispatchTouchEvent返回为true则直接在这一层消费掉了.

模拟7:GrandparentViewdispatchTouchEvent返回为false,点击ChildView部分

  1. GrandparentView dispatchTouchEvent ACTION_DOWN
  2. Activity onTouchEvent ACTION_DOWN
  3. Activity onTouchEvent ACTION_UP

dispatchTouchEvent返回为false,则并不消费,但也不分发.而是反向询问.

onInterceptTouchEvent

用于拦截事件

模拟8:ParentViewonInterceptTouchEvent返回为true,点击ChildView部分

  1. GrandparentView dispatchTouchEvent ACTION_DOWN
  2. GrandparentView onInterceptTouchEvent ACTION_DOWN
  3. ParentView dispatchTouchEvent ACTION_DOWN
  4. ParentView onInterceptTouchEvent ACTION_DOWN <–到这里中断了,直接反向询问
  5. ParentView onTouchEvent ACTION_DOWN
  6. GrandparentView onTouchEvent ACTION_DOWN
  7. Activity onTouchEvent ACTION_DOWN
  8. Activity onTouchEvent ACTION_UP

由于在ParentView中中断事件分发.于是在传到ParentView中直接调用了ParentViewonTouchEvent,然而ParentView并没有消费此事件于是反向询问直到最后.