ScrollView嵌套ListView出现的问题:ListView中有10项Item,但却只显示了一项,虽说可以手动修改ListView的高度,但是ListView的Item数目是不定的,所以有一下解决方法:
1、手动设置ListView高度
经过测试发现,在xml中直接指定ListView的高度,是可以解决这个问题的,但是ListView中的数据是可变的,实际高度还需要实际测量。于是手动代码设置ListView高度的方法就诞生了。
/** * 动态设置ListView的高度 * @param listView */ public static void setListViewHeightBasedOnChildren(ListView listView) { if(listView == null) return; ListAdapter listAdapter = listView.getAdapter(); if (listAdapter == null) { // pre-condition 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外的其他布局的这个方法就是直接抛异常的,没理由…。我最初使用的就是这个方法,但是因为子控件的顶层布局是RelativeLayout,所以一直报错,不得不放弃这个方法。
二是需要手动把ScrollView滚动至最顶端,因为使用这个方法的话,默认在ScrollView顶端的项是ListView,具体原因不了解
2、使用LinearLayout取代ListView
既然ListView不能适应ScrollView,那就换一个可以适应ScrollView的控件,干嘛非要吊死在ListView这一棵树上呢?而LinearLayout是最好的选择。但如果我仍想继续使用已经定义好的Adater呢?我们只需要自定义一个类继承自LinearLayout,为其加上对BaseAdapter的适配。
import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.widget.BaseAdapter; import android.widget.LinearLayout; /** * 取代ListView的LinearLayout,使之能够成功嵌套在ScrollView中 * @author terry_龙 */ public class LinearLayoutForListView extends LinearLayout { private BaseAdapter adapter; private OnClickListener onClickListener = null; /** * 绑定布局 */ public void bindLinearLayout() { int count = adapter.getCount(); this.removeAllViews(); for (int i = 0; i < count; i++) { View v = adapter.getView(i, null, null); v.setOnClickListener(this.onClickListener); addView(v, i); } Log.v("countTAG", "" + count); } public LinearLayoutForListView(Context context) { super(context); } }
上面的代码拷贝保存为LinearLayoutForListView.class,或者直接拷贝Demo中的这个类在自己的工程里。我们只需要把原来xml布局文件中的ListView替换为这个类就行了:
<pm.nestificationbetweenscrollviewandabslistview.mywidgets.LinearLayoutForListView android:id="@+id/act_solution_3_mylinearlayout" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" > </pm.nestificationbetweenscrollviewandabslistview.mywidgets.LinearLayoutForListView>
在Activity中也把ListView改成LinearLayoutForListView,就能成功运行了。
mylinearlayout = (LinearLayoutForListView) findViewById(R.id.act_solution_3_mylinearlayout); adapter = new AdapterForListView(this); mylinearlayout.setAdapter(adapter);
3、自定义可适应ScrollView的ListView
下面是继承了ListView的自定义类:
import android.content.Context; import android.util.AttributeSet; import android.widget.ListView; 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); } }
这个方法和方法1有一个同样的毛病,就是默认显示的首项是ListView,需要手动把ScrollView滚动至最顶端。
sv = (ScrollView) findViewById(R.id.act_solution_4_sv); sv.smoothScrollTo(0, 0)