Android ViewGroup 中处理event

来源:互联网 发布:走近科学 知乎 编辑:程序博客网 时间:2024/05/29 08:29

Case:

     自定义一个ViewGroup,子View包含N个TextView。当用户拖动或者双指放大ViewGroup时,由ViewGroup处理。当用户点击到某个TextView时,TextView接管事件,做更新操作。

Solution on Internet:

    搜索了很久资料,主要有2份有价值的说明,一份来自android:http://developer.android.com/training/gestures/viewgroup.html. 一份来自另外一篇对该文章的解读。

如果完全按照说明,我相信大家一定会遇到如下问题:

   当手指放到没有TextView的地方进行拖动或者放大,获取到的坐标值正常。当手指放到Textview上再进行拖动或者缩放,会发现ViewGroup上的Textview布局会抖动。但是点击TextView却可以正常工作。


Root Clause:

   从现象来看,在ViewGroup中进行onLayout时,如果现实出现了抖动,那么说明,获取到的坐标不正确。因为dispatchDraw里面是根据Layout之后的坐标进行draw的。而android官网告诉我们,在

onInterceptTouchEvent中,如果判断是ACTION_MOVE,那么就return TRUE,这样所有后续ACTION_MOVE事件都会传给ViewGroup的onTouchEvent。但是这里有个问题,ACTION_DOWN事件没有传给onTouchEvent。然而, 所有的onScroll或者onScale事件,都需要ACTION_DOWN事件发生时的坐标。仔细分析源码可知,GestureDetector和ScaleGestureDetector在判断是否onScroll和onScale事件发生,都依赖ActionDown事件。所以没有获取到ACTION_DOWN是所有问题的根源。正确的理解:     1.   Android在处理事件的时候,有个传递机制,就是一直传递直到有事件处理函数返回TRUE。     2. 在ViewGroup中,由于ViewGroup也是一个View。当事件直接发生在这个ViewGroup上,事件将直接送个ViewGroup的onTouchEvent。包括ACTION_DOWN,ACTION_MOVE,ACTION_UP.     3. 在ViewGroup中,如果事件发生的位置有ChildView。那么ViewGroup会先把事件发给
onInterceptTouchEvent。这是保证让ViewGroup有机会决定事件是自己处理完成就ok了还是继续给ChildView。Return TRUE那么ChildView就不会处理了。那么该事件就继续发送给ViewGroup的onTouchEvent.这里换句话表达就是。当事件发生在ChildView上,ViewGroup缺省会让onInterceptTouchEvent处理。然后再根据情况,发送给自己的ViewGroup onTouchEvent或者ChildView的onTouchEvent。Solution:    有了正确的理解,方案就简单了。   1. 因为需求是拖动或者缩放,无论ACTION_DOWN发生在ChilidView还是ViewGroup上,都要有效。那么,在ChildView上时,我们需要在
onInterceptTouchEvent实现。当发生在ViewGroup上时,由于此时
onInterceptTouchEvent不会被调用,所以必须在ViewGroup的onTouchEvent中进行处理。   2. 因为需求是点击TextView时,由TextView接管事件。由于在TextView上发生的事件,首先会调用
onInterceptTouchEvent。所以在onTercetTouchEvent中,针对非ACTION_MOVE都return false.保证时间可以发送个TextView的onTouchEvent.   3. 为了避免用户在拖动的时候,触发TextView的click事件,所以在
onInterceptTouchEvent中,判断是否是ACTION_MOVE事件,如果是,return TRUE。保证不会把事件发送给TextView,避免TextView误判为Click事件。这个问题,花费了我大概6、7个小时的时间解决,同时网上也有人提出类似问题,没有看到详细答案。如果大家有问题,可以给我留言。


1 0
原创粉丝点击