上一回已经分析了view的事件分发,接着这次开始对ViewGroup的事件分发做一些分析,如有不对的地方,劳烦大神赐教。
在这里也推介一篇写的不错的博客:https://blog.csdn.net/binbinqq86/article/details/82315399
引用楼上博客里的一张事件分发图片(红色备注为自己归纳):
我们先自定义一个viewgroup和view.给他们都设在触摸事件和点击事件。
把整体布局上一张图:
最理想(未修改任何的事件分发)的状态情况一 (被点击的子控件为可点击的控件)
然后点击子控件如下
这边的父控件为RootLinearLayout,子控件为MyLinearLayout01.发现事件分发是从父控件到子控件的,dispatchTouchEvent为最先执行,紧接着为事件拦截的onInterceptTouchEvent(默认不拦截false),当事件传到触摸的子控件时,开始执行其事件分发的dispatchTouchEvent,onInterceptTouchEvent。接着会执行它的onTouch,接着OnTouchEvent.然后由于一个控件是可点击的,执行完其事件分发的down后会返回true.接着就由于触摸事件的层级传递开始父类的move事件分发,直到最后的点击事件。父控件的onTouch和OnTouchEvent和点击事件都被略过了,不会执行。
最理想的状态情况二,被点击的子控件为不可点击的控件
发现父控件的点击事件得到了执行,而子控件只执行了其事件分发的一系列down事件。在其onTouchEvent的down事件之后(返回值为super/false)这边可理解为它告诉父类,自己不处理这次的事件了,下次事件分发别再发到我这边来了。开始向上回溯onTouch和onTouchEvent(回溯过程中不能有返回true的onTouchEvent,否则事件分发将断在哪里不再向上回溯,接着从父类分发事件到这),最终会回溯到Activity中返回true开启事件的下一次move事件分发。这次的事件分发在执行完dispatchTouchEvent后不再执行事件拦截的分发(我理解为子控件已经明确表示不处理事件了,所以已决定不向下分发事件,过拦截也多余),也不再向下传递事件,会执行父控件的onTouch和OnTouchEvent,直到最后父控件的点击事件。
如果在返回值中返回true,那将不会回溯事件,我将它理解为事件它告诉父控件,我返回true,我要处理这次的事件。所以事件分发之后会再次从父控件开始move事件,down都会分发到自己这边,类似自己是可点击的控件一样效果。
总体分析完了这两种之后,开始细致分析每一个。。
(1)dispatchTouchEvent
1.1 重写MyLinearLayout01的dispatchTouchEvent返回true.效果如下图
1.2 重写MyLinearLayout01的dispatchTouchEvent返回false.效果如下图
子控件的事件基本没处理事件,仔细观察发现,执行完子控件的down后会回溯父控件的onTouch/onTouchEvent到Activity.
然后开启下一个事件move的分发,事件分发交给父类自己处理。(正常情况下不会去改写dispatchTouchEvent)
(2)onInterceptTouchEvent分析
默认是返回false(返回super效果等同),不进行事件的拦截。如果返回true,就会拦截事件,交给自己处理。对于子控件,可以以有办法打破父控件的事件拦截。通过调用requestDisallowInterceptTouchEvent方法设置成true,往上的父控件的全部拦截都将失效。
当拦截的控件不可点击时,效果如下图
交给自己处理,然自己是不可点击的,执行完onTouchEvent并回溯onTouchEvent,之后的视角就由父控件接手了。
如果linearlayout01为可点击的控件,效果如下:
linearlayout01会处理全部事件。
如果此时我在根布局中的move中返回true拦截事件,那linearlayout01在处理完一次的down完整流程后将收不到后面的其它事件,事件分发到根布局的move会拦截住交给自己处理。然后执行自己的onTouchEvent.最后点击事件也失效了,因为根布局失去了onTouchEvent的down事件。效果图如下
一旦确定拦截,后面的拦截事件也不会再去执行。
下面加入一首插曲:就是如果子控件是listview(可滑动控件的情况)
如果我在onInterceptTouchEvent的up中进行拦截,效果如下
listview可以滑动,但是其item的点击事件就失效了。
如果在move中进行拦截,效果如下
listview将不能滑动,因为listview也属于viewgroup故日志中只有其2行日志,剩下的事件全部由父控件处理。这对于屏蔽滑动冲突有一定的实用性。插曲到此结束,言归正传
3.分析onTouch
三个控件都设置了onTouchListener和点击事件。在中间一个控件的onTouch中返回true。这种情况下中间的onTouch得不到执行,还是执行了第三个控件的点击事件。
如果第三个控件是不可点击的,
事件到达第三个控件后会把onTouch/onTouchEvent向上回溯,回溯到中间控件时,发现其是可点击的,就会结束回溯。重新从父控件开始下一次的事件分发到此。最后中间控件的点击事件也得到了执行。
4. onTouchEvent分析
控件不可点击(或者返回false,super)都会向上回溯onTouchEvent事件,如果回溯过程碰到可点击的控件,就会结束回溯,事件交给那个控件。
累。。。事件分发的分析就到此结束,如有说错的地方,劳烦大神赐教。让我们共同学习,共同进步。