以下文章转自@安卓泡面
在工作中,曾多次碰到ScrollView嵌套ListView的问题,网上的解决方法有很多种,但是杂而不全。我试过很多种方法,它们各有利弊。
在这里我将会从使用ScrollView嵌套ListView结构的原因、这个结构碰到的问题、几种解决方案和优缺点比较,这4个方面来为大家阐述、分析、总结。
实际上不光是ListView,其他继承自AbsListView的类也适用,包括ExpandableListView、GridView等等,为了方便说明,以下均用ListView来代表。
一、 为什么要使用ScrollView嵌套ListView的奇怪的结构
ScrollView和ListView都是滚动结构,按理说,这两个控件在UI上的功能是一样的,但是看看下面这个设计:
这是天猫商城的确认订单的页面,ScrollView中嵌套了ExpandableListView,ExpandableListView上面有固定的一些控件,下面也有固定的一些控件,整体又要能够滚动。 列表数据要嵌在固定数据中间,并且作为整体一起滚动,有了这样的设计需求,于是就有了ScrollView嵌套ListView的奇怪结构。
二、 ScrollView、ListView嵌套结构碰到的问题
不多说,直接看失败例子:
- <ScrollView
- android:id="@+id/act_solution_1_sv"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
- <TextView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="\nListView上方数据\n" />
- <ListView
- android:id="@+id/act_solution_1_lv"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content">
- </ListView>
- <TextView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="\nListView下方数据\n" />
- </LinearLayout>
- </ScrollView>
ScrollView中只能放一个控件,一般都放LinearLayout,orientation属性值为vertical。在LinearLayout中放需要呈现的内容。ListView也在其中,ListView的高度设为适应自身内容(wrap_content)。粗略一看,应该没有什么问题。但是看下面的实际效果图:
图中黑框的部分就是ListView,里面放了20条数据,但是却只显示了1条。
控件的属性设置上没有问题,但是为什么没有按照我的想法走呢?
看看下面这个图:
是否有点明白了呢?原因就是scroll事件的消费处理以及ListView控件的高度设定问题。
解决方案:
自定义可适应ScrollView的ListView
这个方法和上面的方法是异曲同工,方法3是自定义了LinearLayout以取代ListView的功能,但如果我脾气就是倔,就是要用ListView怎么办?那就只好自定义一个类继承自ListView,通过重写其onMeasure方法,达到对ScrollView适配的效果。
下面是继承了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);
- }
- }
GridView跟上面的解决方案一样。