现象:
1.ListView只会显示一行多一点
2.listview不滚动
我们看到只要ScrollView可以滑动,内部的ListView是不能滑动的
在ScrollView中嵌套使用ListView,ListView只会显示一行多一点。两者进行嵌套,即会发生冲突。
由于ListView本身都继承于ScrollView,一旦在ScrollView中嵌套ScrollView,
那么里面的ScrollView高度计算就会出现问题。
我们也就无法得到想要的效果。
下面进入正题,我们将讨论ScrollView中嵌套ListView情况。
核心解决方案: 重写ListView或者GridView的OnMesure 方法。对GridView同样适用。
public class Mylistview extends ListView {
public Mylistview(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
public Mylistview(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public Mylistview(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
//解决listview高度问题;
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
int me = MeasureSpec.makeMeasureSpec(600, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, me);
}
}
1.为什么listview没有滑动。
但是却又onTouch和onScrollview的监听事件
说明事件的消费不消费和是ontouchEvent,有关
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
listView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
@Override
public void onScrollChange(View view, int i, int i1, int i2, int i3) {
Log.d("MainActivity","onScrollChange");
}
});
}
listView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
Log.d("MainActivity","onTouch");
return false;
}
});
得根据实际的需求来确定拦截的规则。这里我们的需求是当ListView滑到顶部了,并且继续向下滑就让ScrollView拦截掉;
当ListView滑到底部了,并且继续向下滑,就让ScrollView拦截掉,其余时候都交给ListView自身处理事件。
什么时候拦截:要想要父类滑动,就拦截,否则不拦截
解决办法
1.外拦截
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
boolean intercepted = false;
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
nowY = y;
intercepted = super.onInterceptTouchEvent(event);
break;
}
case MotionEvent.ACTION_MOVE: {
if(myListView.getFirstVisiblePosition()==0
&& y>nowY){
intercepted = true;
break;
}
else if(myListView.getLastVisiblePosition()==myListView.getCount()-1
&& y<nowY){
intercepted = true;
break;
}
intercepted = false;
break;
}
case MotionEvent.ACTION_UP: {
intercepted = false;
break;
}
default:
break;
}
return intercepted;
}
}
2.内部拦截法
先重写ScrollView的onInterceptTouchEvent方法,让其拦截除了Down事件以外的其他方法:
<span style="color:#000000"><span style="color:#abb2bf"><code><span style="color:#61aeee">@Override</span>
<span style="color:#c678dd">public</span> <span style="color:#c678dd">boolean</span> <span style="color:#61aeee">onInterceptTouchEvent</span>(MotionEvent event) {
<span style="color:#c678dd">int</span> x = (<span style="color:#c678dd">int</span>) event.getX();
<span style="color:#c678dd">int</span> y = (<span style="color:#c678dd">int</span>) event.getY();
<span style="color:#c678dd">int</span> action = event.getAction();
<span style="color:#c678dd">if</span> (action == MotionEvent.ACTION_DOWN) {
mLastX = x;
mLastY = y;
<span style="color:#c678dd">return</span> <span style="color:#c678dd">super</span>.onInterceptTouchEvent(event);
} <span style="color:#c678dd">else</span> {
<span style="color:#c678dd">return</span> <span style="color:#c678dd">true</span>;
}
}</code>
</span></span>
来源: https://www.jianshu.com/p/057832528bdd
在重写ListView的dispatchTouchEvent方法,规则已经说明过了:
<span style="color:#000000"><span style="color:#abb2bf"><code> <span style="color:#61aeee">@Override</span>
<span style="color:#c678dd">public</span> <span style="color:#c678dd">boolean</span> <span style="color:#61aeee">dispatchTouchEvent</span>(MotionEvent event) {
<span style="color:#c678dd">int</span> y = (<span style="color:#c678dd">int</span>) event.getY();
<span style="color:#c678dd">switch</span> (event.getAction()) {
<span style="color:#c678dd">case</span> MotionEvent.ACTION_DOWN: {
nowY = y;
mHorizontalScrollViewEx2.requestDisallowInterceptTouchEvent(<span style="color:#c678dd">true</span>);
<span style="color:#c678dd">break</span>;
}
<span style="color:#c678dd">case</span> MotionEvent.ACTION_MOVE: {
<span style="color:#c678dd">if</span>(<span style="color:#c678dd">this</span>.getFirstVisiblePosition()==<span style="color:#d19a66">0</span>
&& y>nowY){
mHorizontalScrollViewEx2.requestDisallowInterceptTouchEvent(<span style="color:#c678dd">false</span>);
<span style="color:#c678dd">break</span>;
}
<span style="color:#c678dd">else</span> <span style="color:#c678dd">if</span>(<span style="color:#c678dd">this</span>.getLastVisiblePosition()==<span style="color:#c678dd">this</span>.getCount()-<span style="color:#d19a66">1</span>
&& y<nowY){
mHorizontalScrollViewEx2.requestDisallowInterceptTouchEvent(<span style="color:#c678dd">false</span>);
<span style="color:#c678dd">break</span>;
}
mHorizontalScrollViewEx2.requestDisallowInterceptTouchEvent(<span style="color:#c678dd">true</span>);
<span style="color:#c678dd">break</span>;
}
<span style="color:#c678dd">case</span> MotionEvent.ACTION_UP: {
<span style="color:#c678dd">break</span>;
}
<span style="color:#c678dd">default</span>:
<span style="color:#c678dd">break</span>;
}
<span style="color:#c678dd">return</span> <span style="color:#c678dd">super</span>.dispatchTouchEvent(event);
}</code></span></span>
方法三:自己独创
原理:listview不滚动,但是ontouch事件还是有的。
1.listviewOntouch事件处理
listView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
Log.d("MainActivity","onTouch");
if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
//点击listview里面滚动停止时,scrollview拦截listview的触屏事件,就是scrollview该滚动了
mysrollview.requestDisallowInterceptTouchEvent(false);
} else {
//当listview在滚动时,不拦截listview的滚动事件;就是listview可以滚动,
mysrollview.requestDisallowInterceptTouchEvent(true);
}
return false;
}
});
}
2.listview的onScollview方法,不是setOnScrollChangeListener方法哦
listView.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView absListView, int i) {
}
@Override
public void onScroll(AbsListView absListView, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if((firstVisibleItem+visibleItemCount)==totalItemCount){
//如果listview部分加载到最后一条了 ,拦截listview的触屏事件,意思就是scrollview可以滚动了;
mysrollview.requestDisallowInterceptTouchEvent(false);
}
}
});
总结:
其实现在都用RecyclerView代替ListView,ScrollView嵌套RecyclerView时,对于手势已经支持得很好,不必自己处理冲突。这个在demo里也有写,做个对比
但是实际却没有达到效果,查了说mScrollView.scrollTo(x, y)首次初始化时无效果。
最后我用了mScrollView.smoothScrollTo(0,0);
1.ScrollView嵌套ListView手势冲突
2.scrollview嵌套listview滚动冲突解决方案;
3.Android事件分发机制及滑动冲突解决方案
4.View的事件分发机制和滑动冲突解决方案(优秀)
探讨了ScrollView中嵌套ListView导致的滑动冲突问题,提供了三种解决方案:重写ListView的OnMeasure方法、使用外拦截和内拦截法,以及自创的处理方式,通过onTouch和onScroll事件控制。

5000

被折叠的 条评论
为什么被折叠?



