实习中遇到了ScrollView里放置一个ListView的情况,照常书写代码测试的时候出现这种情况:
就是只显示一个item的高度。上网搜索了之后才知道是ScrollView嵌套ListView会无法正确计算高度,导致只显示一个item的高度。
网上解决的思路也有很多,一种是不要在ScrollView里放置ListView,换成其他的布局方式比如ScrollView+LinearLayout或者直接用ListView在其headview里完成需要的复杂布局等等。第二种思路就是既然无法计算正确高度就重写高度测量的方法来达到解决问题的目的。
就第二种思路又有多种方法,以下是我测试过的方法均可以解决这个问题。
第一种方法:写一个方法重新测量高度并设置给listview即可。
public static void setListViewHeightBasedOnChildren(ListView listView) {
//获得adapter
MyAdapter adapter = (MyAdapter) listView.getAdapter();
if (adapter == null) {
return;
}
int totalHeight = 0;
for (int i = 0; i < adapter.getCount(); i++) {
View listItem = adapter.getView(i, null, listView);
listItem.measure(0, 0);
//计算总高度
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
//计算分割线高度
params.height = totalHeight + (listView.getDividerHeight() * (adapter.getCount() - 1));
//给listview设置高度
listView.setLayoutParams(params);
}
在设置完adapter后调用下这个方法即可。
MyAdapter adapter = new MyAdapter();
listview.setAdapter(adapter);
setListViewHeightBasedOnChildren(listview);
显示效果如下:
但是这个方法也有个缺点,就是ScrollView里面必须是LinearLayout,如果不是就没有效果。
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none"></ListView>
</LinearLayout>
</ScrollView>
第二种方法:就是自定义一个ListView重写onMeasure方法
package com.sy.mylistview;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ListView;
/**
* Created by SY on 2016/6/15.
*/
public class MyListView extends ListView {
public MyListView(Context context) {
super(context);
}
public MyListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//重新设置高度
heightMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);这个方法就是根据传入的大小和模式生成一个MeasureSpec类型的32位int值。用两位来表示模式,剩下30位表示大小。 所以传入的Integer.MAX_VALUE >> 2就是30位的最大值,模式是MeasureSpec.AT_MOST即表示子视图最多只能是specSize中指定的大小,最大不超过这个大小。关于onMeasure方法的详解可以看http://blog.csdn.net/guolin_blog/article/details/16330267来理解。
最后只要把原来的ListView换成自定义的ListView就可以了,一样可以正常显示了。
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.sy.mylistview.MyListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none"></com.sy.mylistview.MyListView>
</ScrollView>