ScrollView,ListView等带滚动条控件嵌套解决方案汇总
Posted IyangcLove
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ScrollView,ListView等带滚动条控件嵌套解决方案汇总相关的知识,希望对你有一定的参考价值。
开发中可能遇到各种需求 ViewPager+ListView(首页顶部轮播图+产品/新闻列表)是特别常见的一种需求,这里就需要用到外部的ScrollView 嵌套一个内部的ListView 进行一个显示,直接写的话 ScrollView 的滚动条会覆盖掉ListView的滚动条 使它无法滚动,下面是网上收集的一些解决方案,还有一些开发中遇到的一点小技巧,让这种需求更简单的搞定。
1、手动设置ListView高度
经过测试发现,在xml中直接指定ListView的高度,是可以解决这个问题的,但是ListView中的数据是可变的,实际高度还需要实际测量。于是手动代码设置ListView高度的 方法就诞生了。
// 动态设置ListView的高度
// 此方法在对应的Adapter中定义,这里是ListAdapter。
// 设置适配器后调用此方法传入对应的ListView就可以了
public 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,猜测应该是ListView调用方法的时候重新设置宽高导致的一些焦点抢夺问题,对于这个问题有小技巧 下面会讲到。
2、使用单个ListView取代ScrollView中所有内容
在我的文章android ListView显示多个类型item 和 item中控件抢夺焦点解决办法中有说到,不知道的盆友可以去看看。
3、使用LinearLayout取代ListView
既然ListView不能适应ScrollView,那就换一个可以适应ScrollView的控件,干嘛非要吊死在ListView这一棵树上呢?而LinearLayout是最好的选择。通过addView(View v)方法 可以依次添加item 只是这种方式的适配性很差 如果item少且固定可以考虑使用。
4、自定义可适应ScrollView的ListView
自定义一个类继承自ListView,通过重写其onMeasure方法,达到对ScrollView适配的效果。
下面是继承了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);
MeasureSpec属性不了解的可以参考
http://blog.csdn.net/kaixinbingju/article/details/8649218
这个方法和方法1有一个同样的毛病,就是默认显示的首项是ListView,需要手动把ScrollView滚动至最顶端。
sv = (ScrollView) findViewById(R.id.act_solution_4_sv);
sv.smoothScrollTo(0, 0);
接下来讲小技巧,方法4和方法1 应该是使用得最多的吧,其实可以不用手动滚动回去的,只需要设置ListView上方控件或者父控件的一个属性
android:focusableInTouchMode="true" //需要注意的是 有时候设置父控件属性时会不起作用,具体情况不知。
下面给出方法4的相关代码,可直接拷贝使用
自定义的NoScrollListView
public class NoScrollListView extends ListView
public NoScrollListView(Context context)
super(context);
public NoScrollListView(Context context, AttributeSet attrs)
super(context, attrs);
public NoScrollListView(Context context, AttributeSet attrs, int defStyleAttr)
super(context, attrs, defStyleAttr);
//MeasureSpec.EXACTLY:当我们将控件的layout_width或layout_height指定为具体数值时如andorid:layout_width="50dip",
// 或者为FILL_PARENT是,都是控件大小已经确定的情况,都是精确尺寸。
//MeasureSpec.AT_MOST是最大尺寸,当控件的layout_width或layout_height指定为WRAP_CONTENT时,控件大小一般随着控件的子空间或内容进行变化,
// 此时控件尺寸只要不超过父控件允许的最大尺寸即可。因此,此时的mode是AT_MOST,size给出了父控件允许的最大尺寸。
//MeasureSpec.UNSPECIFIED是未指定尺寸,这种情况不多,一般都是父控件是AdapterView,通过measure方法传入的模式。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
item_lv.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingLeft="10dp">
<ImageView
android:id="@+id/iv"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center_horizontal"
android:background="#ff0000"/>
<TextView
android:id="@+id/item"
android:layout_width="100dp"
android:layout_height="100dp"
android:gravity="fill_vertical"
android:text="TextTextTestScrollView and ListView"
android:textColor="#ff0000"
android:textSize="30sp" />
<!--android:textColor="#1fa67a"-->
</LinearLayout>
Activity
public class ScrollActivity extends Activity
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.scroll_activity);
ListView listView = (ListView) findViewById(R.id.lv);
listView.setAdapter(new MyAdapter());
class MyAdapter extends BaseAdapter
@Override
public int getCount()
return 20;
@Override
public Object getItem(int position)
return null;
@Override
public long getItemId(int position)
return 0;
@Override
public View getView(int position, View convertView, ViewGroup parent)
if (convertView == null)
convertView = getLayoutInflater().inflate(R.layout.item_lv, null);
return convertView;
scroll_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<!-- 在LinearLayout 或者ImageView中设置android:focusableInTouchMode属性都可以达到效果 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:focusableInTouchMode="true" >
<ImageView
android:layout_width="match_parent"
android:layout_height="200dp"
android:src="@mipmap/ic_launcher"
/>
<cd.com.hslistview.NoScrollListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/lv"
>
</cd.com.hslistview.NoScrollListView>
</LinearLayout>
</ScrollView>
</LinearLayout>
大家可以去掉属性测试 再添加属性进行测试,本人一直在用,是完全没问题的。
本文参考链接:http://www.devstore.cn/essay/essayInfo/945.html
以上是关于ScrollView,ListView等带滚动条控件嵌套解决方案汇总的主要内容,如果未能解决你的问题,请参考以下文章
解决ScrollView中嵌套ListView滚动效果冲突问题
使用LinearLayout实现ListView,解决ListView和ScrollView滚动冲突