ScrollView嵌套ListView事件分发问题(深藏不露的disallowIntercept)
#转载请注明出处,谢谢!
前几天朋友问起ScrollView嵌套ListView,滑动事件只作用于ScrollView,ListView内部无法滑动的问题,他虽然找到了解决办法,但是对其原因还是云里雾里,知其然,不知其所以然。在这里我就带着想知其所以然的朋友们,来探寻下如何解决这类事件分发的问题,我的博客还是以思路为准(这里提供两种解决方案),会稍微解读下源码,首先上图:
问题解决前,滑动ListView,内部item没有动静,倒是整个ScrollView滚动动起来了,自然不是我们想要的。
问题解决后,滑动listView,内部item上下滚动,滑动listView以外的部分,整个ScrollView滚动,完美。
从现象上来看,明显是listView的move事件被ScrollView截获了,其实有经验的朋友应该会发现,一般事件分发的冲突事件都是针对move的,很少会有需要解决点击冲突事件的吧(如果有,说明你还是个菜鸟,开个玩笑!)。想到截获,我们是不是心里有了主意,对,重写"
onInterceptTouchEvent
"方法,返回false,让ScrollView无法截获事件,这样问题是不是就解决了,那么第一种解决方案出来了:
方案一、重写onInterceptTouchEvent方法:
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return false;
}
那么大家可能会问,为啥down事件不截获,move事件就给截获了呢?!这个就是领导和下属的区别,你想啊,做事情肯定是交给下面的人做啊(所以有了事件分发,大部分事都交给下属的下属……干了),如果要下班了,你说是不是领导得第一个走,好一点的领导可能自己走了,还会告诉下面的人也可以下班了(这就是第一种解决方案,遇到好领导,他重写了onInterceptTouchEvent,默认不拦截,所有消息共享)坏领导肯定想让你多加班,多给他带来收益啊,于是就自己走了也不说让你走,继续加班呗!!!现在我们来看一下“dispatchTouchEvent”源码:
从源码上来看,第二种解决方案应该是从disallowIntercept入手了,这个变量从字面意思来看是“不允许拦截”,这个可以有啊,那么是不是有可以设置不允许拦截的方法呢,还真有"requestDisallowInterceptTouchEvent(true)"。希望来了,领导让我们加班,不让我们move,我们是不是可以申请不加班。那么在哪里申请呢,down的时候你不用操心,领导绝对不会拦截,生怕你不干,自然是在move的时候了,这个时候就有了第二种解决方案:
方案二、申请不被拦截:(也可以在listView的onTouch事件中申请,这样就不需要自定义ScrollView了,设置对象是ScrollView)
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
//禁止拦截触摸事件(允许往下传递)
// requestDisallowInterceptTouchEvent(true);
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
//禁止拦截触摸事件(允许往下传递)
requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_UP:
Log.e("up", "dispatch "+ sum);
case MotionEvent.ACTION_CANCEL:
//释放-禁止拦截触摸事件
requestDisallowInterceptTouchEvent(false);
break;
default:
break;
}
return super.dispatchTouchEvent(ev);
}
最后给大家一张事件分发流程图,方便大家更好的理解和吸收:
这是根据源码绘制的流程图,Event进来有两大关卡可以拦截,第一道关卡是disallowIntercept,第二道是onIntercept,只要设置其中任何一个都可以让下面的view顺利得到想要的Event,讲到这里基本就告一段落了,欢迎大家访问我的其他博客!!!
源码较简单,不建议下载,当然也提供下载,这里只提供CSDN的下载:http://download.csdn.net/detail/aiyh0202/9659839