Android进阶之事件拦截处理机制

1 Android控件架构

这里写图片描述

这里写图片描述

这里写图片描述

1 简单的总结

(1)父View优先拦截当前事件,拦截不成功就让子View对当前事件进行拦截。
(2)如果拦截成功的话,就会沿着子view到父View的路径查找onTouchEvent返回true的那个子View,让该子View对该事件进行处理;
(3)同时如果某一个View对当前事件拦截成功的话,当前事件就不会继续分发给这个View的子View。

2 事件分发与处理

2.1 结论

(1)android对事件分发的顺序为:Activity–>PhoneWindow->DecorView->yourView;
(2)android控件对事件处理的优先级:onTouch>onTouchEvent>onClick

2.2 事件分发

android既然可以对事件进行拦截,肯定有某个方法对事件进行的传递或者分发。完成事件分发功能的方法由Activity的dispatchTouchEvent(MotionEvent ev)l来负责:

    public boolean dispatchTouchEvent(MotionEvent ev) {  
            if (ev.getAction() == MotionEvent.ACTION_DOWN) {  
                //该方法为空方法,直接忽略之    
                onUserInteraction();  
            }  
             //把事件ev交给phoneWindow来处理  
             if (getWindow().superDispatchTouchEvent(ev)) {  
                //表明整个事件到此结束,处理完毕  
                return true;  
            }  
            //说明该事件在View中没有得到处理,由Activity自己处理  
            //至于怎么处理博客后面后有说明  
            return onTouchEvent(ev);  
        }  

PhoneWindow方法都做了些什么:

    @Override  
       public boolean superDispatchTouchEvent(MotionEvent event) {  
           return mDecor.superDispatchTouchEvent(event);  
       }  

就是把此次事件直接很光棍的传给DecorView,这个View是所有视图的根视图,Activity界面中你能见到的各个View都是DecorView的子View。

2.3 事件处理

到此为止事件已经分发到View上面,View获取到事件后有两个选择:处理和不处理该事件,如果处理该事件那事件就不会继续向其子View分发下去;否则就继续分发下去交给子View对该事件做同样的判断,其实就是个递归的过程。

先用如下的伪代码也表示一下事件处理流程:

    public boolean dispatchTouchEvent(event){  
      //如果当前View对此事件拦截成功  
      if(this.onInterceptTouchEvent(event)){  
          //由当前View对此事件进行处理  
         //true 表示处理了该事件,false表示没有处理该事件  
            return onTouchEvent(event);  
      }else{//没有拦截成功  
           //交给子类来分发拦截处理  
            return child.dispatchTouchEvent(event);  
      }  
    }  

更直观的用流程图可以如下表示:

这里写图片描述

其实通过上面的代码也可以得出这个结论:当Activity中所有的视图View都不处理该事件的是就交给Activity的onTouchEvent方方来处理。

2.4 分析ViewGroup分发事件

(1)ViewGroup永远不会对拦截,因为他的onInterceptTouchEvent(MotionEvent ev)始终返回的是false!这样DecorView对到来的事件MotionEvent就只有分发到子View并由子View进行拦截和处理此事件了.

(2)View包括直接继承于View的子类因为其父类View没有onInterceptTouchEvent方法,所以没法对事件进行拦截,如果这种View获取到了事件,那么就会执行onTouchEvent方法。

3 图例解析

3.1 情况1

如果A的InterceptTouchEvent返回了true,其余的仍然返回false,那么执行输出的log为:
这里写图片描述

转换成效果图为:

这里写图片描述

可以发现此时A拦截了此次Touch事件,事件不再向A的子控件B、C、D传递。此时所有的action事件比如手指移动ACTION_MOVE或者ACTION_UP等事件都交给A的onTouchEvent方法去处理(当然这是在onTouchEvent方法返回true的情况下,如果返回false经过测试时不会相应这些action的)。B、C、D控件是的事件处理拦截方法和事件处理方法是无法得到执行的。

3.2 情况2

只有B的onIntercepteTouchEvent事件返回了true的情况下,打印的log为
这里写图片描述

转换成效果图为:
这里写图片描述

3.3 情况3

同理可知,C控件的onIntercept方法返回了true的情况下,其余的仍然返回false的情况下,输出log为
这里写图片描述

转换成效果图为

这里写图片描述

3.4 下面说说各个view的onTouchEvent返回true的情况

由于onTouchEvent事件是从子控件到父控件传递的,当D的onTouchEvent返回true的时候,经测试输出效果如下

这里写图片描述

转换成效果图为:
这里写图片描述

经过测试发现,此时D处理了此次Touch事件的各种action,C B D是的onTouchEvent的没有得到执行。

同理当C的onTouchEvent方法返回了true的时候,输出的log如下

这里写图片描述

转换成效果图如下:

这里写图片描述

4 参考链接

android事件拦截处理机制详解

从源码角度分析android事件分发处理机制

Android群英传笔记——第三章:Android控件架构与自定义控件讲解

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页