您的位置:首页 > 其它

常用控件:03_004 ScrollView嵌套ListView实现和其替代方法

2016-01-12 16:28 302 查看
#1 需求
在项目中我们会遇到这样的需求:多种类型的数据集(各个类型的数据集的长度不确定)放到一个可滚动的View中展示

#2 效果图



#3 方法一:ScrollView嵌套ListView
1.原理:多个ListView解决多种不确定长度数据集的显示,而ScrollView解决整体显示滑动的效果;但ListView加载数据后,会发现显示不全,这时候要重新根据其item来设置其高度从而显示全部
2.代码:
(1)xml视图:activity_main.xml、adapter_item1.xml、adapter_item2.xml
activity_main.xml:
<LinearLayout 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"

android:orientation="vertical"

tools:context="com.bpj.listview.MainActivity" >

<TextView

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginTop="15dp"

android:text="ScrollView嵌套ListView:" />

<LinearLayout

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_marginTop="10dp"

android:orientation="horizontal" >

<TextView

android:id="@+id/tv_add1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="点击添加listview1" />

<TextView

android:id="@+id/tv_add2"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginLeft="20dp"

android:text="点击添加listview2" />

</LinearLayout>

<TextView

android:id="@+id/tv_solve"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginTop="15dp"

android:text="点击获取替代方案" />

<ScrollView

android:id="@+id/scrollview"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:layout_marginTop="15dp" >

<LinearLayout

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:orientation="vertical" >

<TextView

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="标题一" />

<ListView

android:id="@+id/listview1"

android:layout_width="match_parent"

android:layout_height="wrap_content" />

<TextView

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="标题二" />

<ListView

android:id="@+id/listview2"

android:layout_width="match_parent"

android:layout_height="wrap_content" />

</LinearLayout>

</ScrollView>

</LinearLayout>

adapter_item1.xml:

<?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="40dp"

android:orientation="vertical" >

<TextView

android:id="@+id/textView1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="item1" />

<TextView

android:layout_gravity="center_horizontal"

android:id="@+id/textView2"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="TextView" />

</LinearLayout>

adapter_item2.xml:

<?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="70dp"

android:orientation="vertical" >

<TextView

android:id="@+id/textView1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginLeft="5dp"

android:text="item2" />

<ImageView

android:layout_gravity="center_horizontal"

android:id="@+id/imageView1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:src="@drawable/ic_launcher" />

</LinearLayout>

(2)数据Bean:BeanItem1、BeanItem2:
public class BeanItem1 {}
public class BeanItem2 {}

(3) MyAdapter1、MyAdapter2:
public class MyAdapter1 extends BaseAdapter {

private Context mContext;
private List<BeanItem1> mList;

public MyAdapter1(Context context,List<BeanItem1> list){
mContext = context;
mList = list;
}

@Override
public int getCount() {
return mList.size();
}

@Override
public Object getItem(int position) {
return mList.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
return View.inflate(mContext, R.layout.adapter_item1, null);
}

}

public class MyAdapter2 extends BaseAdapter {

private Context mContext;
private List<BeanItem2> mList;

public MyAdapter2(Context context,List<BeanItem2> list){
mContext = context;
mList = list;
}

@Override
public int getCount() {
return mList.size();
}

@Override
public Object getItem(int position) {
return mList.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
return View.inflate(mContext, R.layout.adapter_item2, null);
}
}

(4)MainActivity
public class MainActivity extends Activity implements OnClickListener {

private ListView listview1,listview2;
private TextView tv_add1,tv_add2,tv_solve;

private Context context;
private List<BeanItem1> mList1;
private List<BeanItem2> mList2;
private MyAdapter1 mAdapter1;
private MyAdapter2 mAdapter2;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

context = this;
mList1 = new ArrayList<BeanItem1>();
mList2 = new ArrayList<BeanItem2>();

listview1 = (ListView) findViewById(R.id.listview1);
listview2 = (ListView) findViewById(R.id.listview2);
tv_add1 = (TextView) findViewById(R.id.tv_add1);
tv_add2 = (TextView) findViewById(R.id.tv_add2);
tv_solve = (TextView) findViewById(R.id.tv_solve);
tv_add1.setOnClickListener(this);
tv_add2.setOnClickListener(this);
tv_solve.setOnClickListener(this);

initData();

mAdapter1 = new MyAdapter1(context, mList1);
listview1.setAdapter(mAdapter1);
UtilsView.setListViewHeightBasedOnChildren(listview1);
mAdapter2 = new MyAdapter2(context, mList2);
listview2.setAdapter(mAdapter2);
UtilsView.setListViewHeightBasedOnChildren(listview2);

}

private void initData() {

for (int i = 0; i < 6; i++) {
BeanItem1 item1 = new BeanItem1();
mList1.add(item1);
}

for (int i = 0; i < 5; i++) {
BeanItem2 item2 = new BeanItem2();
mList2.add(item2);
}
}

/**
* 当动态添加listview2的item时,listview2 会随着
*/
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.tv_add1:
BeanItem1 item1 = new BeanItem1();
mList1.add(item1);
mAdapter1.notifyDataSetChanged();
UtilsView.setListViewHeightBasedOnChildren(listview1);
break;
case R.id.tv_add2:
BeanItem2 item2 = new BeanItem2();
mList2.add(item2);
mAdapter2.notifyDataSetChanged();
UtilsView.setListViewHeightBasedOnChildren(listview2);
break;
case R.id.tv_solve:
/**
* ScrollView嵌套listView是非常影响效率的,xml通常会提示
*
* 解决方法:LinerLayout动态添加View
*/
MainActivity.this.startActivity(new Intent(MainActivity.this, SolveActivity.class));
break;
}
}
}
(4)UtilsView工具类
public class UtilsView {

public static void setListViewHeightBasedOnChildren(ListView listView){
if(listView == null) return;

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));
listView.setLayoutParams(params);
}
}

5. 问题:不建议使用scrollView嵌套ListView,影响效率,底内存的手机容易报OOM,xml也会提出警告:
The vertically scrolling ScrollView should not contain another vertically scrolling widget (ListView)
#4 方法二:json数据结果改变
可以用一个ListView加载不同类型的item,当这要求后台个的json是单层的,将不同类型数据的条目都集成到一个Object上,只是字段不一样,让后再定义一个字段进行标记,加载不同item,不过要改变数据结构,server麻烦一下或者前段获取到数据后,重新组拼。优点是显示时比较简单,数据类型少时,实现容易,加载速度也快;缺点是重新组拼数据有可能比较麻烦,而且视图本来就是为了进行显示,不能本末倒置因为视图而去改变数据结果,在更复杂的业务逻辑中你会发现这样会很麻烦。

#5 方法三:多个LinerLayout动态添加
1. 原理:用ScrollView加LinerLayout实现,一个Linerlayout表示一种类型的数据,通过遍历数据集动态添加View,这里要注意的是当添加View时,用代码new出来,或用xml引入,要不停的new或inflat,如果只inflate一次,可能报异常如下:

java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
2. 代码:

(1)xml:

activity_resolve.xml

<LinearLayout 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"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.bpj.listview.MainActivity" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="ScrollView中Linerlayout动态添加Item" />

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal" >

<TextView
android:id="@+id/tv_add1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="添加Item1" />

<TextView
android:id="@+id/tv_add2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:text="添加Item2" />
</LinearLayout>

<ScrollView
android:id="@+id/scrollview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="15dp" >

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="标题一" />

<LinearLayout
android:id="@+id/ll_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="vertical" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="标题二" />

<LinearLayout
android:id="@+id/ll_2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</LinearLayout>
</ScrollView>

</LinearLayout>

adapter_item1.xml

<?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="40dp"
android:orientation="vertical" >

<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="item1" />

<TextView
android:layout_gravity="center_horizontal"
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />

</LinearLayout>

adapter_item2.xml

<?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="70dp"
android:orientation="vertical" >

<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:text="item2" />

<ImageView
android:layout_gravity="center_horizontal"
android:id="@+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher" />

</LinearLayout>

(2)Bean
public class BeanItem1 {}
public class BeanItem2 {}

(3)Activity:
public class SolveActivity extends Activity implements OnClickListener{

private LinearLayout ll_1,ll_2;
private TextView tv_add1,tv_add2;

private List<BeanItem1> mList1;
private List<BeanItem2> mList2;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_resolve);

ll_1 = (LinearLayout) findViewById(R.id.ll_1);
ll_2 = (LinearLayout) findViewById(R.id.ll_2);
tv_add1 = (TextView) findViewById(R.id.tv_add1);
tv_add2 = (TextView) findViewById(R.id.tv_add2);
tv_add1.setOnClickListener(this);
tv_add2.setOnClickListener(this);

initData();
setAdapter();

}

private void setAdapter() {
MySimpleAdapter adapter1 = new MySimpleAdapter(this, mList1);
adapter1.setView(ll_1);

MySimpleAdapter adapter2 = new MySimpleAdapter(this, mList2);
adapter2.setView(ll_2);
}

private void initData() {

mList1 = new ArrayList<BeanItem1>();
mList2 = new ArrayList<BeanItem2>();

for (int i = 0; i < 6; i++) {
BeanItem1 item1 = new BeanItem1();
mList1.add(item1);
}

for (int i = 0; i < 5; i++) {
BeanItem2 item2 = new BeanItem2();
mList2.add(item2);
}
}

public void onClick(View v) {
switch (v.getId()) {
case R.id.tv_add1:
View view = View.inflate(SolveActivity.this, R.layout.adapter_item1, null);
ll_1.addView(view);
break;
case R.id.tv_add2:
View view2 = View.inflate(SolveActivity.this, R.layout.adapter_item2, null);
ll_2.addView(view2);
break;
}
}
}
(4)Adapter:
public class MySimpleAdapter {

private Context mContext;
private List<?> mList;

public MySimpleAdapter(Context context,List<?> list){
mContext = context;
mList = list;
}

public void setView(LinearLayout ll){
View covertView;
for (int i = 0; i < mList.size(); i++) {
covertView = View.inflate(mContext, R.layout.adapter_item1, null);
ll.addView(covertView);
}
}
}
优点:不需要嵌套,Linerlayout也写可以写成动态添加到ScrollView中去,Adapter中的View可以是xml也可以直接new出来
缺点:每次都new或inflate,影响效率,可以像ListView的Adapter一样维持一个集合从而复用,具体参照BaseAdapter的源码

Demo下载地址:http://download.csdn.net/detail/baopengjian/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: