Android的事件分发(二)

首先推荐一篇小弟转发的博客事件的传递

非常有启发性的一篇文章

咱们接着前一篇讲,探一探onTouchEvent的底

由于我们希望事件最终交给EventView处理,那么我们来瞧一瞧EventView的onTouchEvent的返回值对事件分发的影响

情景一: EventView的各种假设

返回true

其他的所有方法都是默认的返回值

06-23 11:23:56.680: I/System.out(811): eventView---DOWN事件,自己处理
06-23 11:23:56.700: I/System.out(811): eventView---UP事件,自己处理

事件确实被EventView拿到了,他对整个点击事件做了处理

在ACTION_DOWN时返回false

 
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        System.out.println("view处理事件");
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            System.out.println("eventView---DOWN事件,自己处理");
            return false;
            //break;
        case MotionEvent.ACTION_MOVE:
            System.out.println("eventView---MOVE事件,自己处理");
            break;
        case MotionEvent.ACTION_UP:
            System.out.println("eventView---UP事件,自己处理");
            break;
        case MotionEvent.ACTION_CANCEL:
            System.out.println("eventView---CANCEL事件,自己处理");
            break;
        default:
            break;
        }
        return super.onTouchEvent(event);//在这里为true
    }

此时,我在EventView上做了一个滑动动作

06-23 11:46:24.380: I/System.out(903): eventView---DOWN事件,自己处理
06-23 11:46:24.380: I/System.out(903): group_inner---DOWN事件,自己处理
06-23 11:46:24.560: I/System.out(903): group_inner---MOVE事件,自己处理
06-23 11:46:24.570: I/System.out(903): group_inner---MOVE事件,自己处理
06-23 11:46:24.860: I/System.out(903): group_inner---UP事件,自己处理

 
 

可以看到,由于在ACTION_DOWN的时候返回了false,这个事件会被向上传递,即Group_inner,并且父类,即Group_inner已经记住了你,后面的事件(指DOWN和UP之间的一系列事件)都不会传给你了,他会传给自己的onTouchEvent进行处理.

下面我们再来一个假设,假设所有的View和ViewGroup的onTouchEvent都返回false,事件最终会去哪呢?

 
 
 
 

06-23 12:00:43.200: I/System.out(1088): event_view---DOWN事件,自己处理

06-23 12:00:43.200: I/System.out(1088): group_inner---DOWN事件,自己处理

06-23 12:00:43.200: I/System.out(1088): group_outer---DOWN事件,自己处理

06-23 12:00:43.200: I/System.out(1088): Activity处理事件

06-23 12:00:43.280: I/System.out(1088): Activity开始分发事件

06-23 12:00:43.280: I/System.out(1088): Activity处理事件

06-23 12:00:43.290: I/System.out(1088): Activity开始分发事件

06-23 12:00:43.290: I/System.out(1088): Activity处理事件

事件最终传到了Activity,那么问题又来了,假如Activity的onTouchEvent也返回false呢?

结果和上面的一样,所以,事件最终都会被Activity消费掉

现在假设EventView返回super.onTouchEvent(event)

其实我们最终也只想知道一件事,到底是true还是false呢?

所以我们选择进入他的super.onTouchEvent中去看一看,也就是View.onTouchEvent

8321行这个位置
if (((viewFlags & CLICKABLE) == CLICKABLE ||
                (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)){
                          // do something 
   return true;
}
return false;


根据代码,我们知道,如果这个View是可点击的,那么这个方法最终会返回true,否则,返回false那么,问题又来了,我们这个View究竟是不是可点的呢,答案是yes,由于水平有限,我无法从源码的角度给出解释,我是用View.isClickable测试出来的,如果各位有知道的,请告知为了更进一步的验证,我后面又 View.setClickable(false),这里返回的是false

结论一:如果事件传递到当前的方法,而该方法返回了false,那么这个事件会从当前向上传递,并且都是由上层的来接收,如果传递到上面的也返回这个事件就会消失,而且接收不到下一次事件。如果返回了true,则会接收并消费该事件.如果返回super.onTouchEvent(ev),即调用View.onTouchEvent()。

在我的前一篇博客中,我们已经考虑到一点,即dispatchTouchEvent的返回值对他是有影响的。例如dispatchTouchEvent如果返回true,那么事件是不会向下分发了,也不会调用该View的onTouchEvent,而是在该方法中直接被消费。如果大家看了我之前对dispatchTouchEvent返回值得分析时,也许会注意到一个方法onInterceptTouchEvent,以及他在什么时候被调用了。

我们不妨再回到分发事件的开始,即分发--拦截--处理。

我们注意到,如果dispatchTouchEvent直接返回true,或者false时,onInterceptTouchEvent是不会被调用到的,这个可以看看我在前一篇打印的日志,只有返回super.dispatchTouchEvent时才会被调用。

是时候来看一看onInterceptTouchEvent方法了,其实关于这个方法,在我翻译的那一片博客中,已经有较好的诠释了。这个方法的返回值其实是很好理解的,true表示拦截,false表示方形。

源码的注释:

1.Return true to steal motion events from the children and have them dispatched to this ViewGroup through onTouchEvent().  

2.The current target will receive an ACTION_CANCEL event, and no further   messages will be delivered here

第一句:返回true表示偷走子类的事件,后续的事件都会被转发到该ViewGroup的onTouchEvent中 

第二句:目标视图将会收到一个CANCEL事件,并且后面的事件(指一次动作)他不再收到 

 我们的实验又要开始了  除了改动代码,其他的都是默认返回值.在Group_inner的onInterceptTouchEvent中进行判断,如果是一个DOWN事件,拦截,其他的放行  

06-24 03:00:08.063: I/System.out(623): group_inner---DOWN事件,自己处理  

06-24 03:00:08.112: I/System.out(623): group_inner---MOVE事件,自己处理  

06-24 03:00:08.292: I/System.out(623): group_inner---UP事件,自己处理  

可以看到,Group_inner处理了所有的事件,那么,说好的CANCEL事件呢?

且看下面的分析 ,在Group_inner的onInterceptTouchEvent中进行判断,如果是一个MOVE事件,拦截,其他的放行 

 06-24 03:04:03.653: I/System.out(718): eventView---DOWN事件,自己处理 

 06-24 03:04:03.753: I/System.out(718): eventView---CANCEL事件,自己处理  

06-24 03:04:03.773: I/System.out(718): group_inner---MOVE事件,自己处理  

06-24 03:04:03.803: I/System.out(718): group_inner---MOVE事件,自己处理

  06-24 03:04:03.973: I/System.out(718): group_inner---UP事件,自己处理  

可以看到,第二个MOVE事件,被Group_inner截断的那个事件,转化成了CANCEL事件,传到了EventView,然后,后面的事件他再也没份了 。当然,这是安卓的一种机制,自己的理解就是,如果压根你从最开始都没接触到这个事件,我为什么还要告诉你这个事件已经取。

下面来看看官方文档的解释:

1.For as long as you return false from this function, each following event (up to and including the final up) will be delivered first here and then to the target's onTouchEvent()

2.If you return true from here, you will not receive any following events: the target view will receive the same eventbut with the action {@link MotionEvent#ACTION_CANCEL}, and all further events will be delivered to your onTouchEvent()method and no longer appear here.

 
 

第一句话:如果你返回了false,后续的事件首先会被传递到这儿(根据前面的结论,dispatchTouchEvent必须返回super.dispatchTouchEvent,然后被传递到目标的onTouchEvent()

第二句话:如果你返回了true,后续的事件将不会传递到该方法中,此时被拦截的事件会被转化成ACTION_CANCEL事件传给目标(多半是子孩子),后续的事件将会被传递到该视图的onTouchEvent().


下一篇将会讨论requestDisallowInterceptTouchEvent方法

你可能感兴趣的:(android,事件分发)