TouchEvent
简介
复杂View基本都有点击事件的处理,如若处理不当,则难免造成很差的用户体验。最简单的例子,比如合理利用ViewConfiguration提供的工具变量,用来达到Android一致的触控体验。
Test场景
从几个简易的场景来初步搞清楚事件传递过程,Activity中放置ViewGroup,其中再放置View。分别复写对应类的dispatchTouchEvent、onTouchEvent。
子View放弃
子View放弃,事件又回到Activity,如图。
具体过程:ActionDown时,事件先经dispatch方法,再经onTouch方法,直到最子View表示对Down事件不感兴趣(return false),方法返回。由于Down事件是一系列事件的开始,也是是否show interest的标识,系统通过Down的一些列传递明了了“不感兴趣”的View群,于是以后的事件(Move/Up/…)便不会想下传递,这样也提高了效率。
子View感兴趣
知道了一种模式其实其他的都差不多,只不过此时View的onTouch返回了true,系统知道哪一个View感兴趣,之后的事件就全部发送到这个View,通过dispatch-onTouch路径。
子ViewGroup拦截
这类case要求ViewGroup复写onInterceptTouchEvent并return true,实际测试结果和图中有少许出入,dispatch的时候发现哪一层intercept了,就停止继续传递touch事件,直接传给该层的onTouch方法。也比较好理解。
以上只是简单测试,不过已覆盖了很多使用的场景,通过查看源码我们还可发掘更多dispatch/onTouch方法的纠葛..
DispatchTouchEvent
ViewGroup的dispatch方法才真正有意义,View的dispatch方式主要是分发事件给它本身去调用onTouchEvent,而ViewGroup则是分发给其children,且分发过程是递归执行,遇到ViewGroup会向更深处分发。在这个分发链上一旦遇到dispatchTouchEvent返回true,则终止这个序列。(http://www.cnblogs.com/linjzong/p/4191891.html)
此外,dispatch方法其实感兴趣的是ACTION_DOWN,作为事件的开始,通过dispatch分发并测出target,以后的事件(MOVE/UP/..)就直接传递到target。
OnTouchListener
OnTouchListener优先于onTouchEvent对事件进行消费。而且OnTouchListener多给使用该View的人使用,onTouchEvent则是实现该View的内部触摸逻辑。
总结
传递流程描述,ViewGroups和Views构成树形结构,可以看做Event是从根部向下传递(通过dispatch方法)。其中,遇View会转调onTouchEvent,而它的返回结果决定了dispatch的结果,true代表该View已完全处理,这将导致dispatch链中断;遇ViewGroups则递归调用,直到遇到View为止。
对于ViewGroup来说,它的onTouchEvent只有在其所有child的onTouchEvent返回false(表示都未处理,而onTouchEvent的结果与该View的dispatchTouchEvent返回值一致)、或没有child时,才会被调用(通过super.dispatch,只因为它也是View的子类..)。
关于onIntercept。//TODO
关于onTouchListener和onClickListener。//TODO
对一般自定义View,复写onTouchEvent一般就足够,毕竟这是事件最终目的地和处理的地方。对于ViewGroup得分情况考虑,大多数自定义View继承自现有XXLayout比如自定义一个RelativeLayout,那么一般只需要考虑分到它上面的事件如何处理即可,因此继承onTouchEvent;如果想要更高级别的控制、赶在child处理之前处理事件,可以复写dispatchTouchEvent,毕竟它的onTouchEvent只有在大家都不要时才执行..