最近因为项目的需要,要在一个 ScrollView 中放入一个ListView,虽然不推荐这样的设计,尽量不要让两者嵌套,但有时候还是要不得已而为之。发现 ScrollView中放入ListView后,后者的高度有问题,无论怎么设置高度,大约只显示一行半的高度,除非将ListView的高度设定死,但ListView高度根据数据的不同,高度肯定也不同,如果设置死的话滑动又成问题,想来,ListView本身应该具备滑动功能,两个具备滑动功能的控件嵌套在一起的话,可能就会出问题了吧,父容器可能将子控件的滑动事件覆盖掉了吧,再说,两个控件的高度都无法计算,所以不推荐嵌套在一起使用。
解决思路也很简单, 就是在设置完ListView的Adapter后,根据ListView的子项目重新计算ListView的高度,然后把高度再作为LayoutParams设置给ListView,这样它的高度就正确了。代码如下:
public void setListViewHeightBasedOnChildren(ListView listView) { 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)); ((MarginLayoutParams) params).setMargins(10, 10, 10, 10); listView.setLayoutParams(params); }
在设置ListView的Adapter后调用此方法即可让ListView正确的显示在 ScrollView中。但是要注意的是,ListView的每个Item必须是LinearLayout,不能是其他的,因为其他的Layout(如RelativeLayout)没有重写onMeasure(),所以会在onMeasure()时抛出异常。
解决办法二
重写ListView的onMeasure方法:
@Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int expandSpec = MeasureSpec.makeMeasureSpec( Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, expandSpec); }
详细代码如下:
(1)方法一:
ListViewTest1Activity.java
package com.biao.listview; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.ViewGroup; import android.view.ViewGroup.MarginLayoutParams; import android.widget.ListAdapter; import android.widget.ListView; /** * 手工计算listview高度,再设置回去 * * @date 2014-5-5 下午4:34:57 * @version V1.0 */ public class ListViewTest1Activity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.scrollview_listview_1); ListView listView = (ListView) findViewById(R.id.moreItemsListView); MyAdapter adapter = new MyAdapter(this, map()); listView.setAdapter(adapter); setListViewHeightBasedOnChildren(listView); } /** * 计算listview高度的方法 * @param listView */ public void setListViewHeightBasedOnChildren(ListView listView) { 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)); ((MarginLayoutParams) params).setMargins(10, 10, 10, 10); listView.setLayoutParams(params); } /** * 测试数据 */ private List<HashMap<String, String>> map() { List<HashMap<String, String>> data = new ArrayList<HashMap<String, String>>(); for (int i = 0; i < 20; i++) { HashMap<String, String> map = new HashMap<String, String>(); map.put("name", "测试" + i); data.add(map); } return data; } }
scrollview_listview_1.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#FFF4F4F4" android:orientation="vertical" > <ScrollView android:layout_width="fill_parent" android:layout_height="fill_parent" android:fadingEdge="none" > <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center_horizontal" android:orientation="vertical" > <ListView android:id="@+id/moreItemsListView" android:layout_width="fill_parent" android:layout_height="fill_parent" android:cacheColorHint="#00000000" android:divider="@null" android:dividerHeight="0.0dip" android:fadingEdge="none" /> </LinearLayout> </ScrollView> </LinearLayout>
(2)方法二:
ListViewTest2Activity.java
package com.biao.listview; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import android.app.Activity; import android.os.Bundle; import android.widget.ListView; /** * 使用改写过的onMeasure的listview来重新计算listview高度 * * @date 2014-5-5 下午4:35:42 * @version V1.0 */ public class ListViewTest2Activity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.scrollview_listview_2); ListView listView = (MyListView) findViewById(R.id.moreItemsListView); MyAdapter adapter = new MyAdapter(this, map()); listView.setAdapter(adapter); } /** * 测试数据 */ private List<HashMap<String, String>> map() { List<HashMap<String, String>> data = new ArrayList<HashMap<String, String>>(); for(int i = 0 ; i < 20 ; i++){ HashMap<String, String> map = new HashMap<String, String>(); map.put("name", "测试" + i); data.add(map); } return data; } }
改写listview
MyListVew.java
package com.biao.listview; import android.content.Context; import android.util.AttributeSet; import android.widget.ListView; /** * 唯一有用的是改写了onMeasure,重新计算高度 * * @date 2014-5-5 下午4:46:12 * @version V1.0 */ 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 defStyle) { super(context, attrs, defStyle); } /** * 重写listview高度计算 * * 个人理解,widthMeasureSpec,heightMeasureSpec由父类传过来,这里将高度设置最大为Integer.MAX_VALUE/2的足够高的高度, * 让listview可以完全展现出来,展现完后,再由父类包裹起来,那整个listview就可以展现出来了 * */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2 , MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, expandSpec); } }
布局文件scrollview_listview_2.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#FFF4F4F4" android:orientation="vertical" > <ScrollView android:layout_width="fill_parent" android:layout_height="fill_parent" android:fadingEdge="none" > <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center_horizontal" android:orientation="vertical" > <com.biao.listview.MyListView android:id="@+id/moreItemsListView" android:layout_width="fill_parent" android:layout_height="fill_parent" android:cacheColorHint="#00000000" android:divider="@null" android:dividerHeight="0.0dip" android:fadingEdge="none" /> </LinearLayout> </ScrollView> </LinearLayout>
效果图:
比较方便是重写onMeasure方式,这方式同样适用于scrollview嵌套gridview的情况。
代码见附件