思路梳理
在深入分析事件分发源码之前,需要先弄清楚2个概念。
ViewGroup
ViewGroup 是一组 View 的组合,在其内部有可能包含多个子 View,当手指触摸屏幕上时,手指所在的区域既能在ViewGroup显示范围内,也可能在其内部 View 控件上。因此它内部的事件分发的重心是处理当前 ViewGroup 和子 View 之间的逻辑关系:
-
1.当前 ViewGroup 是否需要拦截Touch事件;
-
2.是否需要将Touch事件继续分发给子 View;
-
3.如何将Touch事件分发给子 View。
View
View 是一个单纯的控件,不能再被细分,内部也并不会存在子 View,所以它的事件分发的重点在于当前 View 如何去处理 Touch 事件,并根据相应的手势逻辑进行一些列的效果展示(比如滑动,放大,点击,长按等)。
-
1.是否存在 TouchListener;
-
2.是否自己接收处理 touch 事件(主要逻辑在 onTouchEvent 方法中)。
涉及事件分发的方法
方法的简单用途解析
我们可以发现这三个方法的返回值都为boolean类型,其实它们就是通过返回值来决定下一步的传递处理方向。
1、dispatchTouchEvent() ——用来分发事件所用
该方法会将Touch事件**「自上而下」依次分发到子元素中,直到被终止或者到达View层,该方法也是采用一种「隧道方式来分发」。在其中会调用onInterceptTouchEvent()和onTouchEvent(),「一般不会重写」**。
-
返回false则不拦截继续往下分发;
-
返回true则拦截住该事件不在向下层元素分发;
在dispatchTouchEvent()方法中默认返回false。
2、onInterceptTouchEvent() ——用来拦截事件所用
-
返回false不拦截事件,Touch事件就会往下传递给其子View。
-
返回true,该事件将会被拦截,并且被当前ViewGroup处理,调用ViewGroup的onTouchEvent()方法。
3、onTouchEvent() ——用来处理事件
-
返回true则表示该View能处理该事件,事件将终止向上传递(传递给其父View)。
-
返回false表示不能处理,则把事件传递给其父View的onTouchEvent()方法来处理。
拥有上述方法的类
「注意:」 需要特别注意一点就是ViewGroup中额外拥有onInterceptTouchEvent()方法,其他两个方法为这三种类所共同拥有。
事件分发流程
单个事件触发后,事件分发流程:Activity①>ViewGroup②>View③,如下图:
即要想充分理解Android分发机制,本质上是要理解:
-
Activity对点击事件的分发机制
-
ViewGroup对点击事件的分发机制
-
View对点击事件的分发机制
从U型图中可以发现,由父组件不断向子组件分发,若子组件能够处理,则立刻返回。若子组件都不处理,那传递到底层的子组件,再返回回来。「整个View之间的事件分发,实质上就是一个大的递归函数」。
实例
==
下面咱们写一个简单实例来更好的理解这个大U型图,效果图: