本文共 4397 字,大约阅读时间需要 14 分钟。
我们继续来学习Android View事件的分发机制,通过前面两篇博客的介绍相信大家对Android View事件的分发机制有了很深的理解。那么今天我们继续学习ViewGroup的事件分发机制。
ViewGroup是View的一个集合,它是继承自View的子类,各种布局也都继承于ViewGroup。ViewGroup实际上也是一个View,只不过比起View,它多了可以包含子View和定义布局参数的功能。在介绍ViewGroup事件的分发机制之前,我们来先看一下第一节三个方法中 onInterceptTouchEvent这个方法的源码:
/** * Implement this method to intercept all touch screen motion events. This * allows you to watch events as they are dispatched to your children, and * take ownership of the current gesture at any point. * *看着挺吓人的,其实只有一句非常简单的代码,返回false。Using this function takes some care, as it has a fairly complicated * interaction with {@link View#onTouchEvent(MotionEvent) * View.onTouchEvent(MotionEvent)}, and using it requires implementing * that method as well as this one in the correct way. Events will be * received in the following order: * *
*
* * @param ev The motion event being dispatched down the hierarchy. * @return Return true to steal motion events from the children and have * them dispatched to this ViewGroup through onTouchEvent(). * The current target will receive an ACTION_CANCEL event, and no further * messages will be delivered here. */public boolean onInterceptTouchEvent(MotionEvent ev) { return false;}- You will receive the down event here. *
- The down event will be handled either by a child of this view * group, or given to your own onTouchEvent() method to handle; this means * you should implement onTouchEvent() to return true, so you will * continue to see the rest of the gesture (instead of looking for * a parent view to handle it). Also, by returning true from * onTouchEvent(), you will not receive any following * events in onInterceptTouchEvent() and all touch processing must * happen in onTouchEvent() like normal. *
- 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(). *
- If you return true from here, you will not receive any * following events: the target view will receive the same event but * with the action {@link MotionEvent#ACTION_CANCEL}, and all further * events will be delivered to your onTouchEvent() method and no longer * appear here. *
2、实际案例
首先我们来自定义一个布局,命名为MyLayout,继承自LinearLayout,如下所示:
然后,打开主布局文件activity_main.xml,在其中加入我们自定义的布局:
分别点击一下Button1、Button2和空白区域,打印结果如下所示:
你会发现,当点击按钮的时候,MyLayout注册的onTouch方法并不会执行,只有点击空白区域的时候才会执行该方法。你可以先理解成Button的onClick方法将事件消费掉了,因此事件不会再继续向下传递。
如果我们把前面的onInterceptTouchEvent方法让它在MyLayout类中返回true。那么 现在再次运行项目,然后分别Button1、Button2和空白区域,打印结果如下所示:
我们发现,不管点击哪里,永远都只会触发MyLayout的touch事件了,按钮的点击事件完全被屏蔽掉了!这也就是第一节中提到的这个函数的功能是用来判断是否拦截某个事件。在这里就发挥了作用。
原因是Android事件的传递规则是Activity======>>>>>>>Windows======>>>>>>ViewGroup======>>>>>View.
它的示意图如下所示:
由于Activity和ViewGroup都是有点击事件的,也就是他们都有dispatchTouchEvent,onInterceptTouchEvent,
onTouchEvent。如果ViewGroup对事件进行了拦截,那么View将不会收到该点击事件。如果对不拦截,则View将收到该事件,并消耗掉该事件。Viewgroup将不会接收到任何事件。
我们可以用流程图来表示上述传递。