Android触摸事件传递(下)

  上一篇中,我说明了Android中Activity和View触摸事件的传递流程,现在我们来继续学习MotionEvent在View的容器ViewGroup中的传递过程。

  首先,ViewGroup继承于View,我们在开发中经常使用的LinearLayout,RelativeLayout,FrameLayout等都继承于ViewGroup,而Button,TextView,ImageView等都继承于View,ViewGroup对View最基本的扩展的功能就是可以添加子View。

  ViewGroup触摸事件的传递,我们要先了解onInterceptTouchEvent()方法,这个方法默认返回false,表示ViewGroup是否拦截触摸事件,即如果返回true,拦截触摸事件,则不会将任何触摸事件ev向下传递给它的子View,换一句话说,这个时候,ViewGroup就变成了我们上一篇说的View,完全走View的触摸事件传递流程,同样的我们来写代码验证。

  我们自定义一个EventRelativeLayout 继承于RelativeLayout,重写onInterceptTouchEvent方法,返回true, 重写onTouchEvent方法,返回false,然后将我们Activity的根布局改成EventRelativeLayout,然后在onCreate中给它添加onTouchListener,

Android触摸事件传递(下)_第1张图片


Android触摸事件传递(下)_第2张图片
Android触摸事件传递(下)_第3张图片

   运行App,点击按钮,查看打印日志,

  

  可以看到,我们的button没有接收到触摸事件,现在将onInterceptTouchEvent返回值改为false,再次运行App,点击按钮,查看打印日志,

Android触摸事件传递(下)_第4张图片

   很明显,我们的按钮的触摸事件和它的父容器的触摸事件,都触发了,这是因为,我们EventBtn的onTouchListener方法和onTouchEvent方法都返回false,没有消费触摸事件,事件会向上继续传递。那么如果ViewGroup不拦截触摸事件,事件在它的子Views中又是如何传递的呢?

   触摸事件ev会按照子View加入ViewGroup先后顺序相反的顺序,依次有机会去消费此触摸事件ev,即最后加入的最先有机会消费此触摸事件,当然,它消费的前提是,触摸点的坐标在这个子View的frame范围之内,其实只需要判断触摸事件的Point是否在子控件的Rect范围之内。我们同样写代码验证。

   重写EventBtn类,如下,

Android触摸事件传递(下)_第5张图片

  修改onCreate中的代码

Android触摸事件传递(下)_第6张图片

    修改main布局文件

Android触摸事件传递(下)_第7张图片

    修改布局文件,让三个按钮完全重合,加入的顺序,分别是btn1,btn2,btn3,如果按照我们的结论,触摸事件的传递顺序应该是btn3->btn2->btn1->ViewGroup->Activity,我们运行App,点击按钮,查看打印日志,


Android触摸事件传递(下)_第8张图片

    我们可以看到,日志 打印的顺序呢,跟我们的结论一致,也就验证了我们的结论。但是我们仔细想来,好像还有点问题,就是我们一个按钮点击的动作,至少应该包含了ACTION_DOWN,ACTION_UP,二个触摸事件,但是我们打印的日志,显然只是一个触摸事件,那这是为什么呢?

    为了搞清楚上面的问题,我们继续来到View的dispatchTouchEvent方法中,我们看到下面的一段代码

Android触摸事件传递(下)_第9张图片

    我们也很好读懂,如果事件是ACTION_UP或者ACTION_CANCEL,表示触摸结束,但是还有第三种是 如果触摸事件是ACTION_DOWN 并且result==false,同样停止嵌套的触摸事件传递,即后面的ACTION_MOVE,ACTION_UP都不会触发,因为在我们上面的例子中,没有消费触摸事件,返回的都是false,所以只触发了ACTION_DOWN事件。同样,我们可以利用代码来验证我们上面的结论,我们打开EventBtn类中dispatchTouchEvent方法中的日志打印代码,同时我们将btn3的onTouchListener方法返回true,消费掉触摸事件,然后运行App,点击按钮,查看日志。

Android触摸事件传递(下)_第10张图片
Android触摸事件传递(下)_第11张图片


Android触摸事件传递(下)_第12张图片

    我们看到,这里一次按钮点击触发了4个事件,分别是ACTION_DOWN,ACTION_MOVE,ACTION_MOVE,ACTION_UP,同时所有事件全部被btn3消费掉了,这就验证了我们上面的结论,因为此时我们让btn3消费了ACTION_DOWN事件,所以后续触摸事件得以继续触发。通过上面的知识,如果我们不希望响应触摸事件,可以给ACTION_DOWN触摸事件,返回false,或者如果我们希望提前结束一个触摸事件周期,可以给targetView 发送 ACTION_CANCEL事件,如下:


    关于Android中ViewGroup的触摸事件传递就介绍到这里,难免很多地方有错误纰漏,但是我能够坚持把这些写出来,我觉得我已经有一点小小的提高了,很开心~~

你可能感兴趣的:(Android触摸事件传递(下))