Android 解决ScrollView嵌入ListView | GridView | ScrollView显示问题

时间:2023-11-10 23:16:32

一、ScrollView中嵌套ListView

ScrollView和ListView都是滚动结构,很明显如果在ScrollView中加入ListView,可以预见性的知道,肯定会有显示/滚动的问题,接下来就分享我在网上找到的方法(有2种方法);

M1、手动设置(计算)ListView的高度

/**
* 动态设置ListView的高度
* @param listView
*/
public static void setListViewHeightBasedOnChildren(ListView listView) {
if(listView == null) return; ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
return;
} int totalHeight = 0;
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
} ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
}

上面这个方法很显然,就是设定ListView的高度了,在为ListView设置了Adapter之后使用,就可以解决问题了。
但是使用这个方法有个细节需要注意:Adapter中getView方法返回的View的必须由LinearLayout组成,因为只有LinearLayout才有measure()方法,如果使用其他的布局如RelativeLayout,在调用listItem.measure(0, 0);时就会抛异常,因为除LinearLayout外的其他布局的这个方法就是直接抛异常的。

M2、自定义ListView,适应嵌入ScrollView中

public class ListViewForScrollView extends ListView {
public ListViewForScrollView(Context context) {
super(context);
} public ListViewForScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
} public ListViewForScrollView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
} @Override
/**
* 重写该方法,达到使ListView适应ScrollView的效果
*/
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}

其实,这个方法也就是重写onMeasure方法,重新计算ListView的高度,不过比第一个方法更加简单简洁;
同样,使用这个方法时,需要注意一点,默认scrollview会滚动到ListView的第一项,此时只需要让scrollview滚动到最顶端即可:

scrollview.smoothScrollTo(0, 0);

二、ScrollView中嵌套GridView
参考ScrollView中嵌套ListView的第二个实现方法,不过有一占小的区别;参见如下代码:

public class GridViewForScrollView extends GridView {   
private boolean haveScrollbar = true;
public GridViewForScrollView(Context context) {
super(context);
}
public GridViewForScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public GridViewForScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
* 设置是否有ScrollBar,当要在ScollView中显示时,应当设置为false。 默认为 true
*
* @param haveScrollbars
*/
public void setHaveScrollbar(boolean haveScrollbar) {
this.haveScrollbar = haveScrollbar;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (haveScrollbars == false) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}

三、ScrollView嵌套ScrollView

        parent.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
parent.requestDisallowInterceptTouchEvent(false);
return false;
}
});
child.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// 禁止parent view响应child view的触摸事件
child.requestDisallowInterceptTouchEvent(true);
return false;
}
});

这个方法的核心在于:当触摸事件发生在child身上时,禁止parent view响应child view的触摸事件;