在做app的时候相信每个人都有遇到过事件冲突吧,比如最常见的scroview嵌套一个listview,不少人一开始遇到这种情况肯定心里冒出一句尼玛这啥玩意,咋跟老子预想不一样,这个时候你就需要了解一下Android的事件传递机制了。
当我们做一个点击事件的时候对于viewgroup而言会重写三个方法dispatchTouchEvent,onInterceptTouchEvent,onTouchEvent。dispatchTouchEvent用于对事件进行分发,接着调用onInterceptTouchEvent询问是否对事件进行拦截,最后调用onTouchEvent对事件进行处理。对于view而言则会执行dispatchTouchEvent,onTouchEvent。
下面看下分析案例吧,首先创建布局:viewgroupParent包含viewgroupChild包含view,如下所示
接下来我们什么都不做,看下点击view时看下会发生什么
通过上图可以总结:
事件的传递顺序:父viewgroup->子viewgroup->view
事件的处理顺序:view->子viewgroup->父viewgroup
我们可以讲父viewgroup看作校长,子viewgroup看作班主任,view看作你,对就是你,现在一个任务下来了,校长觉得简单,自己就可以搞定,校长的onInterceptTouchEvent返回true看下日志
校长把事情干了后,没后面人啥事了,事件到此为止。这时校长假如不想干了,班主任(子viewgroup)说没事任务交给他就可以,这时让班主任的onInterceptTouchEvent返回true,看下日志
所以可以看到这时你(view)就不用干活了
我们知道事件的处理是由view向上传递的,就是你(view)把活干完了还要想班主任(子viewgroup)汇报情况,但是你今天头脑发热想体验下当老大的感觉,这时你(view)把onTouchEvent返回true,看下日志
可以看到事件就被你(view)处理掉了,也不用汇报了。假如你觉得不汇报就自己处理掉不太好,可能会被罚站,于是将结果汇报给了班主任(子viewgroup ),班主任看了后说了句你这是做的啥玩意,都不好意思在给校长看了,于是班主任讲自己的onTouchEvent返回了true,看下日志
当你处理了事件后班主任又处理了一次事件,事件处理到班主任这里就结束了。
总结一下:
想要拦截一个事件一般复写ViewGroup的onInterceptTouchEvent方发,使其返回true
要想事件不被拦截一般让ViewGroup的onInterceptTouchEvent返回false,或者可以在子view调用viewgroup.requestDisallowInterceptTouchEvent(boolean),设为true则不拦截 ,false则为拦截