上面的总结都是基于:若是没有拦截;那么如何拦截呢?java
复写ViewGroup的onInterceptTouchEvent方法:ide
默认是不拦截的,即返回false;若是你须要拦截,只要return true就好了,这要该事件就不会往子View传递了,而且若是你在DOWN retrun true ,则DOWN,MOVE,UP子View都不会捕获事件;若是你在MOVE return true , 则子View在MOVE和UP都不会捕获事件。this
缘由很简单,当onInterceptTouchEvent(ev) return true的时候,会把mMotionTarget 置为null ; spa
若是ViewGroup的onInterceptTouchEvent(ev) 当ACTION_MOVE时return true ,即拦截了子View的MOVE以及UP事件;.net
此时子View但愿依然可以响应MOVE和UP时该咋办呢?orm
Android给咱们提供了一个方法:requestDisallowInterceptTouchEvent(boolean) 用于设置是否容许拦截,咱们在子View的dispatchTouchEvent中直接这么写:blog
getParent().requestDisallowInterceptTouchEvent(true); 这样即便ViewGroup在MOVE的时候return true,子View依然能够捕获到MOVE以及UP事件。事件
从源码也能够解释:ip
ViewGroup MOVE和UP拦截的源码是这样的:get
当咱们把disallowIntercept设置为true时,!disallowIntercept直接为false,因而拦截的方法体就被跳过了~
注:若是ViewGroup在onInterceptTouchEvent(ev) ACTION_DOWN里面直接return true了,那么子View是木有办法的捕获事件的~~~
咱们的实例,直接点击ViewGroup内的按钮,固然直接很顺利的走完整个流程;
可是有两种特殊状况
一、ACTION_DOWN的时候,子View.dispatchTouchEvent(ev)返回的为false ;
若是你仔细看了,你会注意到ViewGroup的dispatchTouchEvent(ev)的ACTION_DOWN代码是这样的
只有在child.dispatchTouchEvent(ev)返回true了,才会认为找到了可以处理当前事件的View,即mMotionTarget = child;
可是若是返回false,那么mMotionTarget 依然是null
mMotionTarget 为null会咋样呢?
其实ViewGroup也是View的子类,若是没有找到可以处理该事件的子View,或者干脆就没有子View;
那么,它做为一个View,就至关于View的事件转发了~~直接super.dispatchTouchEvent(ev);
源码是这样的:
咱们没有一个可以处理该事件的目标元素,意味着咱们须要本身处理~~~就至关于传统的View~
二、那么何时子View.dispatchTouchEvent(ev)返回的为true
若是你仔细看了上篇博客,你会发现只要子View支持点击或者长按事件必定返回true~~
源码是这样的:
关于代码流程上面已经总结过了~
一、若是ViewGroup找到了可以处理该事件的View,则直接交给子View处理,本身的onTouchEvent不会被触发;
二、能够经过复写onInterceptTouchEvent(ev)方法,拦截子View的事件(即return true),把事件交给本身处理,则会执行本身对应的onTouchEvent方法
三、子View能够经过调用getParent().requestDisallowInterceptTouchEvent(true); 阻止ViewGroup对其MOVE或者UP事件进行拦截;
好了,那么实际应用中能解决哪些问题呢?
好比你须要写一个相似slidingmenu的左侧隐藏menu,主Activity上有个Button、ListView或者任何能够响应点击的View,你在当前View上死命的滑动,菜单栏也出不来;由于MOVE事件被子View处理了~ 你须要这么作:在ViewGroup的dispatchTouchEvent中判断用户是否是想显示菜单,若是是,则在onInterceptTouchEvent(ev)拦截子View的事件;本身进行处理,这样本身的onTouchEvent就能够顺利展示出菜单