Android详细教程(基础篇):八、View组件高级篇:ListView详解

版权声明:本文为博主原创文章,转载请注明出处。作者:杨雄进 https://blog.csdn.net/makyan/article/details/89164157

7.2. ListView (列表视图)

与滚动视图(ScrollView)类似的还有一种列表组件(ListView),可以将多个组件加入到ListView之中,以达到组件的

滚动显示效果,ListView组件本身也有对应的ListView类支持,可以通过操作ListView类以完成对此组件的操作。

 列表的显示需要三个元素:

1.ListVeiw :用来展示列表的View,可以写在配置里,也可以在Activity程序中new一个

2.适配器 :用来把数据映射到ListView上的中介。

3.数据 :具体的将被映射的字符串,图片,或者基本组件。

根据列表的适配器类型,列表分为三种,ArrayAdapter,SimpleAdapter和SimpleCursorAdapter

其中以ArrayAdapter最为简单,只能展示一行字。SimpleAdapter有最好的扩充性,可以自定义出各种效果。

SimpleCursorAdapter可以认为是SimpleAdapter对数据库的简单结合,可以方便的把数据库的内容以列表

的形式展示出来。

ListView类的继承结构如下:

java.lang.Object

   

android.view.View

 

   

android.view.ViewGroup

 

 

   

android.widget.AdapterView<T extends android.widget.Adapter>

 

 

 

   

android.widget.AbsListView

 

 

 

 

   

android.widget.ListView

ListView的常用方法:

ListView(Context context)  创建ListView类的实例化对象

public void setAdapter (ListAdapter adapter)  设置显示的数据

public ListAdapter getAdapter ()  返回ListAdapter

public void setOnItemSelectedListener (AdapterView.OnItemSelectedListener listener) 当选项选中时触发此事件

ListAdapter的已知子类:

Known Indirect Subclasses

ArrayAdapter<T>, BaseAdapter, CursorAdapter, HeaderViewListAdapter, ResourceCursorAdapter, SimpleAdapter, SimpleCursorAdapter, WrapperListAdapter

7.2.1. 使用ArrayAdapter来设置ListView组件中的显示数据

  • ArrayAdapter简单介绍

java.lang.Object

   

android.widget.BaseAdapter

 

   

android.widget.ArrayAdapter<T>

public ArrayAdapter (Context context, int textViewResourceId, T[] objects)

context,就是Activity; textViewResourceId,布局方式;存放数据的数组

  • 程序演示:

配置:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    >

<TextView 

    android:layout_width="fill_parent"

    android:layout_height="wrap_content"

    android:text="@string/hello"

    />

</LinearLayout>

程序:

package com.makyan.demo;

import android.app.Activity;

import android.os.Bundle;

import android.widget.ArrayAdapter;

import android.widget.ListView;

public class ArrayAdapterActivity extends Activity {

private String data[] = { "杨雄工作科技", "www.makyan.cn", "讲师:杨雄进",

               "中国高校讲师联盟", "www.makyan.com", "咨询邮箱:[email protected]",

               "客户服务:[email protected] ", "客户电话:085147856987", "杨雄社区:bbs.makyan.cn",

               "我家农产品" }; // 准备出若干个信息而这些信息以后将通过程序加入到内嵌的线性布局文件之中

            private ListView listView = null; // 定义ListView组件

            @Override

            public void onCreate(Bundle savedInstanceState) {

                       super.onCreate(savedInstanceState);

                       listView = new ListView(this); // 实例化组件

                       listView.setAdapter(new ArrayAdapter<String>(this,

                                               android.R.layout.simple_list_item_1, data)); // 为ListView组件设置内容

                       super.setContentView(listView) ;  // 显示组件

       listView.setOnItemClickListener(new OnItemClickListenerImpl());

            }

            private class OnItemClickListenerImpl implements OnItemClickListener{

                       @Override

                       public void onItemClick(AdapterView<?> adapter, View arg1, int position,long id) {

                                    if(id<-1) { 

                                                // 点击的是headerView或者footerView 

                                                return; 

                                    } 

                                   int realPosition=(int)id; 

                                   // 响应代码 

                                   Toast.makeText(ArrayAdapterActivity.this, "您喜欢的是:" + adapter.getItemAtPosition(realPosition), position).show();

                       }

            }

}

  • 演示效果

7.2.2. 使用SimpleAdapter来设置ListView组件中的数据

  • SimpleAdapter简单介绍

java.lang.Object

   

android.widget.BaseAdapter

 

   

android.widget.SimpleAdapter

public SimpleAdapter (Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to)

context:就是Activity。

data:装了Map数据的List。

resource:组件资源。

from:即List中的Map中的key组成的数组。

to:resource对应的文件中的各个组件的资源id组成的数组。

(from和to中的数据要一一对应)

  • 程序演示:

配置:activity_simple_adapter.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

     android:orientation="vertical" android:layout_width="fill_parent"

     android:layout_height="fill_parent">

     <TextView

          android:layout_width="fill_parent"

          android:layout_height="wrap_content"

          android:textSize="25px"

          android:gravity="center_horizontal"

          android:text="信息列表" />

     <ListView

          android:id="@+id/datalist"

          android:layout_width="fill_parent"

          android:layout_height="wrap_content"/>

</LinearLayout>

展示格式配置dta_list.xml

<TableLayout

     xmlns:android="http://schemas.android.com/apk/res/android"

     android:layout_width="fill_parent"

     android:layout_height="wrap_content">

     <TableRow>

          <ImageView

               android:id="@+id/icon"

               android:layout_height="wrap_content"

               android:layout_width="wrap_content"

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

          <TextView

               android:id="@+id/_id"

               android:textSize="15px"

               android:gravity="center_vertical"

               android:layout_width="wrap_content"

               android:layout_height="wrap_content" />

          <TextView

               android:id="@+id/name"

               android:textSize="15px"

               android:gravity="center_vertical"

               android:layout_width="wrap_content"

               android:layout_height="wrap_content" />

     </TableRow>

</TableLayout>

SimpleAdapterActivity

package com.example.listviewsimpleadapterproject;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import android.app.Activity;

import android.os.Bundle;

import android.widget.ListView;

import android.widget.SimpleAdapter;

public class SimpleAdapterActivity extends Activity {

     private String data[][] = { { "001", "杨雄工作科技" },

               { "002", " www.makyan.cn " }, { "003", "讲师:杨雄进" },

               { "004", "中国高校讲师联盟" }, { "005", " www.makyan.com " },

               { "006", "咨询邮箱:[email protected] " }, { "007", "客户服务:[email protected] " },

               { "008", "客户电话:085147856987" }, { "009", "杨雄社区:bbs.makyan.cn " },

               { "010", "我家农产品" } }; // 准备出若干个信息而这些信息以后将通过程序加入到内嵌的线性布局文件之中

     private ListView datalist = null; // 定义ListView组件

     private List<Map<String, String>> list = new ArrayList<Map<String, String>>(); // 定义显示的内容包装

     private SimpleAdapter simpleAdapter = null; // 进行数据的转换操作

     public void onCreate(Bundle savedInstanceState) {

          super.onCreate(savedInstanceState);

          super.setContentView(R.layout.activity_simple_adapter);

          datalist = (ListView) super.findViewById(R.id.datalist); // 取得组件,通过配置取得ListView

          for (int x = 0; x < data.length; x++) {

               Map<String, String> map = new HashMap<String, String>(); // 定义Map集合,保存每一行数据

               map.put("_id", data[x][0]); // 与data_list.xml中的TextView组件匹配

               map.put("name", data[x][1]); // 与data_list.xml中的TextView组件匹配

               list.add(map); // 保存了所有的数据行

          }

          simpleAdapter = new SimpleAdapter(this, list,

                    R.layout.data_list, new String[] { "_id", "name" } // Map中的key的名称

                    , new int[] { R.id._id, R.id.name }); // 是data_list.xml中定义的组件的资源ID

          datalist.setAdapter(simpleAdapter);

     }

}

运行效果就不贴了,很简单。

SimpleAdater另一复杂例子:

配置文件:activity_simple_adapter_activity2.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

     android:orientation="vertical" android:layout_width="fill_parent"

     android:layout_height="fill_parent">

     <TextView

          android:layout_width="fill_parent"

          android:layout_height="wrap_content"

          android:textSize="25px"

          android:gravity="center_horizontal"

          android:text="杨雄工作室视频列表" />

     <ListView

          android:id="@+id/datalist"

          android:layout_width="fill_parent"

          android:layout_height="wrap_content"/>

</LinearLayout>

展示格式配置dta_list.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout

     xmlns:android="http://schemas.android.com/apk/res/android"

     android:orientation="horizontal"

     android:layout_width="fill_parent"

     android:layout_height="wrap_content">

     <ImageView

          android:id="@+id/pic"

          android:layout_height="wrap_content"

          android:layout_width="wrap_content"

          android:padding="3px"/>

     <LinearLayout

          android:orientation="vertical"

          android:layout_width="150px"

          android:layout_height="wrap_content"

          android:gravity="left">

          <TextView

               android:id="@+id/title"

               android:textSize="16px"

               android:padding="3px"

               android:layout_width="wrap_content"

               android:layout_height="wrap_content" />

          <TextView

               android:id="@+id/author"

               android:padding="3px"

               android:textSize="10px"

               android:layout_width="wrap_content"

               android:layout_height="wrap_content" />

     </LinearLayout>

     <LinearLayout

          android:orientation="vertical"

          android:layout_width="200px"

          android:layout_height="wrap_content"

          android:gravity="left">

          <TextView

               android:id="@+id/type"

               android:padding="3px"

               android:layout_width="wrap_content"

               android:layout_height="wrap_content" />

          <ImageView

               android:id="@+id/score"

               android:padding="3px"

               android:layout_width="wrap_content"

               android:layout_height="wrap_content" />

     </LinearLayout>

</LinearLayout>

程序:

package com.makyan.demo;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import android.app.Activity;

import android.os.Bundle;

import android.widget.ListView;

import android.widget.SimpleAdapter;

public class SimpleAdapterActivity2 extends Activity {

     private int pic[] = new int[] { R.drawable.pic_oracle,

               R.drawable.pic_javase, R.drawable.pic_javaweb,

               R.drawable.pic_javaee, R.drawable.pic_android, R.drawable.pic_game };

     private String data[][] = new String[][] { { "Oracle数据库", "杨雄工作室" },

               { "Java SE基础课程", "杨雄进" }, { "Java WEB综合开发", "MAKYAN" },

               { "Java EE高级开发", "杨雄进" }, { "Android嵌入式开发", "杨雄进" },

               { "Java 游戏开发", "makyan" } };

     private ListView datalist = null; // 定义ListView组件

     private List<Map<String, String>> list = new ArrayList<Map<String, String>>(); // 定义显示的内容包装

     private SimpleAdapter simpleAdapter = null; // 进行数据的转换操作

     @Override

     public void onCreate(Bundle savedInstanceState) {

          super.onCreate(savedInstanceState);

          super.setContentView(R.layout.activity_simple_adapter_activity2);

          datalist = (ListView) super.findViewById(R.id.datalist); // 取得组件

          for (int x = 0; x < data.length; x++) {

               Map<String, String> map = new HashMap<String, String>(); // 定义Map集合,保存每一行数据

               map.put("pic", String.valueOf(pic[x])); // 与data_list.xml中的TextView组加匹配

               map.put("title", data[x][0]); // 与data_list.xml中的TextView组加匹配

               map.put("author", data[x][1]); // 与data_list.xml中的TextView组加匹配

               map.put("type", "免费");

               map.put("score", String.valueOf(R.drawable.start_05));

               list.add(map); // 保存了所有的数据行

          }

          simpleAdapter = new SimpleAdapter(this, list,

                    R.layout.data_list, new String[] { "pic", "title", "author",

                              "type", "score" } // Map中的key的名称

                    , new int[] { R.id.pic, R.id.title, R.id.author, R.id.type,

                              R.id.score }); // 是data_list.xml中定义的组件的资源ID

          datalist.setAdapter(simpleAdapter);

     }

}

7.2.3. 使用SimpleCursorAdapter来设置ListView中的数据

sdk的解释是这样的:

An easy adapter to map columns from a cursor to TextViews or ImageViews defined in an XML file. You can specify which columns you want, which views you want to display the columns, and the XML file that defines the appearance of these views。

简单的说就是方便把从游标得到的数据进行列表显示,并可以把指定的列映射到对应的TextView中。

  下面的程序是从电话簿中把联系人显示到类表中。先在通讯录中添加一个联系人作为数据库的数据。然后获得一个指向数据库的Cursor并且定义一个布局文件(当然也可以使用系统自带的)。

/**

 * @author allin

 *

 */

public class MyListView2 extends Activity {

  

    private ListView listView;

    //private List<String> data = new ArrayList<String>();

    @Override

    public void onCreate(Bundle savedInstanceState){

        super.onCreate(savedInstanceState);

          

        listView = new ListView(this);

          

        Cursor cursor = getContentResolver().query(People.CONTENT_URI, null, null, null, null);

        startManagingCursor(cursor);

          

        ListAdapter listAdapter = new SimpleCursorAdapter(this, android.R.layout.simple_expandable_list_item_1, 

                cursor,

                new String[]{People.NAME}, 

                new int[]{android.R.id.text1});

          

        listView.setAdapter(listAdapter);

        setContentView(listView);

    }

      

      

}

Cursor cursor = getContentResolver().query(People.CONTENT_URI, null, null, null, null);先获得一个指向系统通讯录数据库的Cursor对象获得数据来源。

 startManagingCursor(cursor);我们将获得的Cursor对象交由Activity管理,这样Cursor的生命周期和Activity便能够自动同步,省去自己手动管理Cursor。

 SimpleCursorAdapter 构造函数前面3个参数和ArrayAdapter是一样的,最后两个参数:一个包含数据库的列的String型数组,一个包含布局文件中对应组件id的int型数组。其作用是自动的将String型数组所表示的每一列数据映射到布局文件对应id的组件上。上面的代码,将NAME列的数据一次映射到布局文件的id为text1的组件上。

注意:需要在AndroidManifest.xml中如权限:<uses-permission android:name="android.permission.READ_CONTACTS"></uses-permission>

运行后效果如下图:

7.2.4. 在ListView中,给里面的组件添加事件监听:

  1. 有按钮的ListView

但是有时候,列表不光会用来做显示用,我们同样可以在在上面添加按钮。添加按钮首先要写一个有按钮的xml文件,然后自然会想到用上面的方法定义一个适配器,然后将数据映射到布局文件上。但是事实并非这样,因为按钮是无法映射的,即使你成功的用布局文件显示出了按钮也无法添加按钮的响应,这时就要研究一下ListView是如何现实的了,而且必须要重写一个类继承BaseAdapter。下面的示例将显示一个按钮和一个图片,两行字如果单击按钮将删除此按钮的所在行。并告诉你ListView究竟是如何工作的。效果如下:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="horizontal" 

    android:layout_width="fill_parent"

    android:layout_height="fill_parent">

  

  

    <ImageView android:id="@+id/img" 

        android:layout_width="wrap_content"

        android:layout_height="wrap_content" 

        android:layout_margin="5px"/>

  

    <LinearLayout android:orientation="vertical"

        android:layout_width="wrap_content" 

        android:layout_height="wrap_content">

  

        <TextView android:id="@+id/title" 

            android:layout_width="wrap_content"

            android:layout_height="wrap_content" 

            android:textColor="#FFFFFFFF"

            android:textSize="22px" />

        <TextView android:id="@+id/info" 

            android:layout_width="wrap_content"

            android:layout_height="wrap_content" 

            android:textColor="#FFFFFFFF"

            android:textSize="13px" />

  

    </LinearLayout>

  

  

    <Button android:id="@+id/view_btn"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="@string/s_view_btn"

        android:layout_gravity="bottom|right" />

</LinearLayout>

程序代码:

/**

 * @author allin

 * 

 */

public class MyListView4 extends ListActivity {

  

  

    private List<Map<String, Object>> mData;

      

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        mData = getData();

        MyAdapter adapter = new MyAdapter(this);

        setListAdapter(adapter);

    }

  

    private List<Map<String, Object>> getData() {

        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();

  

        Map<String, Object> map = new HashMap<String, Object>();

        map.put("title", "G1");

        map.put("info", "google 1");

        map.put("img", R.drawable.i1);

        list.add(map);

  

        map = new HashMap<String, Object>();

        map.put("title", "G2");

        map.put("info", "google 2");

        map.put("img", R.drawable.i2);

        list.add(map);

  

        map = new HashMap<String, Object>();

        map.put("title", "G3");

        map.put("info", "google 3");

        map.put("img", R.drawable.i3);

        list.add(map);    

        return list;

    }

      

    // ListView 中某项被选中后的逻辑

    @Override

    protected void onListItemClick(ListView l, View v, int position, long id) {

          

        Log.v("MyListView4-click", (String)mData.get(position).get("title"));

    }

    /**

     * listview中点击按键弹出对话框

     */

    public void showInfo(){

        new AlertDialog.Builder(this)

        .setTitle("我的listview")

        .setMessage("介绍...")

        .setPositiveButton("确定", new DialogInterface.OnClickListener() {

            @Override

            public void onClick(DialogInterface dialog, int which) {

            }

        })

        .show();

       

    }

    public final class ViewHolder{

        public ImageView img;

        public TextView title;

        public TextView info;

        public Button viewBtn;

    }

    public class MyAdapter extends BaseAdapter{

        private LayoutInflater mInflater;

        public MyAdapter(Context context){

            this.mInflater = LayoutInflater.from(context);

        }

        @Override

        public int getCount() {

            // TODO Auto-generated method stub

            return mData.size();

        }

        @Override

        public Object getItem(int arg0) {

            // TODO Auto-generated method stub

            return null;

        }

        @Override

        public long getItemId(int arg0) {

            // TODO Auto-generated method stub

            return 0;

        }

        @Override

        public View getView(int position, View convertView, ViewGroup parent) {      

            ViewHolder holder = null;

            if (convertView == null) {         

                holder=new ViewHolder();          

                convertView = mInflater.inflate(R.layout.vlist2, null);

                holder.img = (ImageView)convertView.findViewById(R.id.img);

                holder.title = (TextView)convertView.findViewById(R.id.title);

                holder.info = (TextView)convertView.findViewById(R.id.info);

                holder.viewBtn = (Button)convertView.findViewById(R.id.view_btn);

                convertView.setTag(holder);            

            }else {           

                holder = (ViewHolder)convertView.getTag();

            }

            holder.img.setBackgroundResource((Integer)mData.get(position).get("img"));

            holder.title.setText((String)mData.get(position).get("title"));

            holder.info.setText((String)mData.get(position).get("info"));

              

            holder.viewBtn.setOnClickListener(new View.OnClickListener() {

                  

                @Override

                public void onClick(View v) {

                    showInfo();                 

                }

            });     

            return convertView;

        }

    }

}

下面将对上述代码,做详细的解释,listView在开始绘制的时候,系统首先调用getCount()函数,根据他的返回值得到listView的长度(这也是为什么在开始的第一张图特别的标出列表长度),然后根据这个长度,调用getView()逐一绘制每一行。如果你的getCount()返回值是0的话,列表将不显示同样return 1,就只显示一行。

  系统显示列表时,首先实例化一个适配器(这里将实例化自定义的适配器)。当手动完成适配时,必须手动映射数据,这需要重写getView()方法。系统在绘制列表的每一行的时候将调用此方法。getView()有三个参数,position表示将显示的是第几行,covertView是从布局文件中inflate来的布局。我们用LayoutInflater的方法将定义好的vlist2.xml文件提取成View实例用来显示。然后将xml文件中的各个组件实例化(简单的findViewById()方法)。这样便可以将数据对应到各个组件上了。但是按钮为了响应点击事件,需要为它添加点击监听器,这样就能捕获点击事件。至此一个自定义的listView就完成了,现在让我们回过头从新审视这个过程。系统要绘制ListView了,他首先获得要绘制的这个列表的长度,然后开始绘制第一行,怎么绘制呢?调用getView()函数。在这个函数里面首先获得一个View(实际上是一个ViewGroup),然后再实例并设置各个组件,显示之。好了,绘制完这一行了。那再绘制下一行,直到绘完为止。在实际的运行过程中会发现listView的每一行没有焦点了,这是因为Button抢夺了listView的焦点,只要布局文件中将Button设置为没有焦点就OK了。

运行效果如下图:

小结:

  1. 使用ListView可以进行数据的列表显示
  2. 对于ListView显示的数据可以使用ArrayAdapter和SimpleAdapter进行封装
  3. 列表操作也可以进行事件的监听处理

 

猜你喜欢

转载自blog.csdn.net/makyan/article/details/89164157