ScrollView嵌套ListView
在开发中,我们常会用到在一个可以滑动的界面中添加ListView(不止一个,否则直接使用一个ListView或
ScrollView就可以了)的情况,这就是ScrollView嵌套ListView。
就像上边一样的布局:整体是一个可以滑动的ScrollView,中间有三个ListView,而且每个ListView的item数量不一定。
注意:
①:若没有给ListView加id,在预览视图中是看不到ListView的;
②:如果给每个ListView都设置固定高度,则会出现整体ScrollView可以滑动,而每个ListView不能滑动(并不是完全不能滑动,若一个手指按住屏幕不动,另一个手指滑动ListView,是可以滑动的),这样就会出现ListView高度固定导致item不能全部显示的问题。
需求的实现思路:
- 布局设置:根据需求,每个ListView的高度设置为自适应
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.com.MainActivity" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="第一个ListView"
android:textColor="#f00"
android:textSize="20sp"/>
<ListView
android:id="@+id/listView1"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="第一个ListView"
android:textColor="#f00"
android:textSize="20sp"/>
<ListView
android:id="@+id/listView2"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="第一个ListView"
android:textColor="#f00"
android:textSize="20sp"/>
<ListView
android:id="@+id/listView3"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
</LinearLayout>
</ScrollView>
- 定义Adapter
public class ListViewAdapter extends BaseAdapter{
Context context;
List<ItemEntity> items=null;
public ListViewAdapter(Context context,List<ItemEntity> entities) {
super();
this.context=context;
this.items=entities;
}
static class ViewHolder{
private TextView name;
private TextView sexes;
}
@Override
public int getCount() {
return items.size();
}
@Override
public Object getItem(int position) {
return items.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null){
convertView=LayoutInflater.from(context).inflate(R.layout.list_view_adapter_layout,null);
viewHolder=new ViewHolder();
viewHolder.name=(TextView)convertView.findViewById(R.id.name);
viewHolder.sexes=(TextView)convertView.findViewById(R.id.sexes);
convertView.setTag(viewHolder);
}else{
viewHolder=(ViewHolder)convertView.getTag();
}
viewHolder.name.setText(items.get(position).getName());
viewHolder.sexes.setText(items.get(position).getSexes());
return convertView;
}
}
- 子Item的布局(在ScrollView嵌套ListView的问题中,Item的布局必须是LinearLayout,只有它有onMeasure()方法)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="8dp"/>
<TextView
android:id="@+id/sexes"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|right"
android:layout_marginRight="8dp"/>
</LinearLayout>
- 存放数据的实体类
package com.example.com;
public class ItemEntity {
private String name;
private String sexes;
public ItemEntity() {
super();
}
public ItemEntity(String name, String sexes) {
super();
this.name = name;
this.sexes = sexes;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSexes() {
return sexes;
}
public void setSexes(String sexes) {
this.sexes = sexes;
}
}
- Activity实现,setListViewHeightBasedOnChildren(ListView listView)方法计算整个ListView的高度,然后赋值给ListView,此方法应该在setAdapter()之后调用。
public class MainActivity extends Activity {
private List<ItemEntity> items=null;
private ListViewAdapter adapter;
private ListView listView1;
private ListView listView2;
private ListView listView3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
private void init() {
items=new ArrayList<ItemEntity>();
adapter=new ListViewAdapter(getApplication(), items);
listView1=(ListView)findViewById(R.id.listView1);
listView2=(ListView)findViewById(R.id.listView2);
listView3=(ListView)findViewById(R.id.listView3);
items.add(new ItemEntity("德瑪","男"));
items.add(new ItemEntity("男槍","男"));
items.add(new ItemEntity("火女","女"));
items.add(new ItemEntity("奧巴馬","男"));
items.add(new ItemEntity("武器大師","男"));
items.add(new ItemEntity("瑞茲","男"));
items.add(new ItemEntity("女槍","女"));
items.add(new ItemEntity("石頭人","男"));
listView1.setAdapter(adapter);
listView2.setAdapter(adapter);
listView3.setAdapter(adapter);
setListViewHeightBasedOnChildren(listView1);
setListViewHeightBasedOnChildren(listView2);
setListViewHeightBasedOnChildren(listView3);
}
public static void setListViewHeightBasedOnChildren(ListView listView) {
// 获取ListView对应的Adapter
ListAdapter listAdapter = listView.getAdapter();
if(listAdapter == null) {
return;
}
int totalHeight = 0;
for(int i = 0, len = listAdapter.getCount(); i < len; i++) { // listAdapter.getCount()返回数据项的数目
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(0, 0); // 计算子项View 的宽高
totalHeight += listItem.getMeasuredHeight(); // 统计所有子项的总高度
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight
+ (listView.getDividerHeight() * (listAdapter.getCount() - 1));
// listView.getDividerHeight()获取子项间分隔符占用的高度
// params.height最后得到整个ListView完整显示需要的高度
listView.setLayoutParams(params);
}
}
在这个Demo中,三个ListView的数据是写死的,在实际应用中,可以加载不同数量不同形式的数据。
另外一种情况
上边说过,ListView的Item数量是不固定的,那么如果这个ListView没有数据,难道只显示一个标题,然后下边的ListView部分省略,下边接着一个标题+ListView吗??
这样显然是不合理的,我们应该在ListView没有数据的时候显示提示语(或者直接省略这个标题和ListVew)。
这里有一个在ListView没有数据的时候显示提示语的例子。
(参考http://www.cnblogs.com/mengdd/archive/2013/08/28/3287662.html)
<!--
The frame layout is here since we will be showing either
the empty view or the list view.
-->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1" >
<!--
Here is the list. Since we are using a ListActivity, we
have to call it "@android:id/list" so ListActivity will
find it
-->
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:drawSelectorOnTop="false" />
<!-- Here is the view to show if the list is emtpy -->
<TextView
android:id="@android:id/empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="No items."
android:textAppearance="?android:attr/textAppearanceMedium" />
</FrameLayout>
android:id=”@android:id/empty”
这个属性值的作用就是,当ListView关联的Adapter中数据为空时,就显示这个TextView。
而这个ListView中有数据显示时,这个TextView是不可见的。
以上,就是ScrollView嵌套ListView的整个实现过程,如有问题,欢迎大家指出!