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

来源:互联网 发布:合肥飞恒网络 编辑:程序博客网 时间:2024/06/08 15:55
#1 需求
    在项目中我们会遇到这样的需求:多种类型的数据集(各个类型的数据集的长度不确定)放到一个可滚动的View中展示

#2 效果图
ss
#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/


1 0
原创粉丝点击