scrollview与listview共存

最近因为项目的需要,要在一个 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>

 

效果图:

scrollview与listview共存_第1张图片

 

 

 

比较方便是重写onMeasure方式,这方式同样适用于scrollview嵌套gridview的情况。

 

 

代码见附件

 

你可能感兴趣的:(scrollview)