论Andriod的Touch事件分发

本文是对Android的Touch事件分发的一个总结。

因为是总结,偏向代码讲解的部分几乎没有,如果看代码有疑问,倒可以来我这找找灵感。毕竟先知道原理然后再看代码,会更容易理解。

Touch事件分发。首先,从流程上,大致分两部分。
第一部分,从事件的产生到传递到Activity之前。第二部分,事件在本页的View中传递。
一般后半部分谈到的比较多,而前半部分由于可自定义等方面的价值不高,比较少关注。下面讲后半部分。
涉及两个类,View /ViewGroup
涉及主要的四个方法,
dispatchTouchEvent,
onInterceptTouchEvent,
onTouchEvent,
dispatchTransformedTouchEvent;
第一个方法是最核心的。第四个方法是新版本的Android才有的,老版的写法有些不太一样的地方。
实际的分发过程逻辑,很复杂,因为参杂很多要处理的因素(维度)。为了做相对初略的了解,我们一般只考虑比较核心的几个因素。
比如说,第一个,onInterceptTouchEvent。这就是个比较简单的维度,表示是否拦截。如果拦截,事件就不按视图层次往下分发。
onTouchEvent,基本算是一个重点。事件分发最终会调用某层某个View的该方法。
而dispatchTransformedTouchEvent类似于执行 dispatchTouchEvent 的必经之地。
dispatchTouchEvent主要做的是外围的大逻辑,而其中一般会调用到 dispatchTransformedTouchEvent, 去做一些小逻辑。
很多的讲解都是有点总结性质的,这些话可以考虑看完以下细节,再回过头来看。
在我阅读的过程中,最疑惑的问题在一个地方 TouchTarget,后来参考了其他人的一些相关的讲解,有点懂了。

TouchTarget 是一个很基本的要素,必须有。

这涉及到一个核心的思想或者原则。
一个完整的触摸事件应该是怎样的?由哪些构成,有哪些特点??
1.必定是由 Down(都有哪些类型的事件就不补了,不是本文的核心)事件开始,然后由Up结束。
2.一般也有滑动,也就有Move的加入,复杂点比如多点触控,还会涉及 Point_up ,point_down;
3.特别情况下还会有撤销(cancel)事件,(这个我也还没总结)。
有过一点总结后,就能想到,事件一般就是由Down作为开始的,所以Down的处理尤为重要。
当Down处理完了(找到处理该Down事件的View时),这个目标View就会被记录, TouchTarget 要登场了
这个私有内部类的名字意义就是 Touch的目标。 记录以后,一个完整的触摸事件的后续Touch事件(比如Move,比如Up)就会被直接传给该目标View,
而不再重走一堆麻烦冗长的寻找目标View的路。而完整的走完后,有新的Down事件来了,就会做一次记录清理,干掉TouchTarget里的值。 这是很重要的一个思想, 掌握思想,看代码会更好理解。

而 TouchTarget 在类里面,最重要的化身就是 mFirstTouchTarget 这个成员变量。

在这里,我抛一个问题,为下面的内容做个铺垫。当然思路上一般都不是按我这样走的。
TouchTarget 其实没有设计的那么简单,存一个View。实际他是一个链表,用 next成员变量 把一个个 TouchTarget 链接起来。而 mFirstTouchTarget 仅仅是整个链中的表头。而且,类还设计了一个 pointerIdBits 用于存放 pointerId (存的是组合值,也就是多个,原文注释:The combined bit mask of pointer ids for all pointers captured by the target.) 。还有 sRecycleBin 。
为啥设计这么复杂呢?
其实像 sRecycleBin 是为了重复利用,避免一直开辟新对象, 还有 用bit去做 pointerId 的值组合。这样比较高效,占用空间不大,而且做位运算,也挺快的。
这些都是加分点,也是效率上的要求而做的。但都不是核心。
核心是多点触控。当有多个View要同时接收各自的事件时,这会用上。多点触控的时候,第一,目标View可能多个,第二,单个View中的点(point)也可能有多个。
这使得,链表和pointid组合值,都是必要的。

下面简要讲一下,分发的决定过程。

当上一层把事件分发到这一层的时候,这一层会考虑把事件分发给底下哪个View(当然这时候就先不考虑拦截的情况)。
首先肯定先把所有子项列出来。然后挨个查,比如验证该视图是否可见,是否可接受触控事件,比如转换触控坐标(转成子视图下的相对坐标)验证该点是否在该子视图内,等等。如果该子项满足种种条件,就会分发给他。
这时候要提一下另一个要点, boolean handled。 事件传到的每层都有权力选择处理或者不处理,也理解为是否消费该 Touch事件。当某个View消费了,那就算真正找到目标了。如果没有子View消费该事件,该GroupView就会降级,当自己是普通的View,调用View.dispatchTouchEvent去分发,当然实际上没有什么分发的逻辑,View本身已经代表视图树的枝叶了,只是考虑是否消费而已。比如这时候会考虑是否有设置 OnTouchListener,如果有,会调用。同样的,OnTouchListener也有是否消费的权利。 最后考虑的,是View的 onTouchEvent.基本上 onTouchEvent等级最低。
主观上的感觉是,如果暂时没有找到愿意消费的,就会继续分发去找,有点接近视图树遍历的感觉,直接有人消费,传递过程就结束了。

如果都没有呢?是否传回Activity的 dispatchTouchEvent? 这个涉及 前半部分的逻辑?等我看完代码,再总结

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值