ListView

来源:互联网 发布:mac os 病毒查杀 编辑:程序博客网 时间:2024/06/06 04:52

Android中ListView这个组件比较常用,但对初学者来说,又比较难掌握,在此分享一下我的使用经验。
ListView是以列表的形式展示数据,这里面有三个要素:数据、视图、适配器。
常用的适配器有三种:ArrayAdapter, SimpleAdapter, SimpleCursorAdapter。 【这种方法仅仅适用于每一个item形式都相同的情况】
其中SimpleAdapter扩展性最好,几乎能实现所有展示需求的列表,我在实际开发中用的全是这个,这里也只介绍这个。

假设要实现如下效果的列表视图:

下面一步步来实现。

首先设计视图,主要设计ListView里面item的显示效果,在layout中创建item.xml文件,如下:

Xml代码  收藏代码
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="fill_parent" android:layout_height="75dp"  
  4.     android:paddingLeft="10dp" android:paddingRight="10dp">  
  5.     <ImageView  
  6.         android:id="@+id/img"  
  7.         android:layout_height="fill_parent"  
  8.         android:layout_width="60dp"  
  9.         android:layout_alignParentLeft="true" />  
  10.     <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  11.         android:orientation="vertical" android:layout_height="fill_parent"  
  12.         android:layout_width="fill_parent" android:layout_toRightOf="@id/img"  
  13.         android:paddingLeft="8dp">  
  14.         <TextView  
  15.             android:id="@+id/title1"  
  16.             android:layout_width="wrap_content"  
  17.             android:layout_height="wrap_content"  
  18.             android:textColor="#cbcaca"  
  19.             android:textSize="20dp" />  
  20.         <TextView  
  21.             android:id="@+id/title2"  
  22.             android:layout_width="wrap_content"  
  23.             android:layout_height="wrap_content"  
  24.             android:textColor="#cbcaca"  
  25.             android:textSize="14dp" />  
  26.         <TextView  
  27.             android:id="@+id/time"  
  28.             android:layout_width="wrap_content"  
  29.             android:layout_height="wrap_content"  
  30.             android:textColor="#cbcaca"  
  31.             android:textSize="12dp" />  
  32.     </LinearLayout>  
  33.     <CheckBox  
  34.         android:id="@+id/checked"  
  35.         android:layout_height="fill_parent"  
  36.         android:layout_width="wrap_content"  
  37.         android:layout_alignParentRight="true"  
  38.         android:checked="false"  
  39.         android:focusable="false" />  
  40. </RelativeLayout>  

此xml文件定义列表中每个项目的布局,如果想要不同的布局,修改此文件的布局即可。

这个文件中给每个需要在程序中动态赋值的地方都取了id,看到后面的代码时,注意对应关系。

 

然后是适配器和数据,这两个联系比较紧密,就放一起了。

先上代码:

Java代码  收藏代码
  1. //获取ListView对象  
  2. ListView mListView = (ListView) findViewById(R.id.listview);
  3. //下面是数据映射关系,mFrom和mTo按顺序一一对应
  4. String[] mFrom = new String[] {"img""title1""title2""time"};
  5. int[] mTo = new int[] {R.id.img, R.id.title1, R.id.title2, R.id.time};
  6. //获取数据,这里随便加了10条数据,实际开发中可能需要从数据库或网络读取
  7. List<Map<String, Object>> mList = new ArrayList<Map<String, Object>>();
  8. Map<String,Object> mMap = null;
  9. for (int i = 0; i < 10; i++) {
  10.     mMap = new HashMap<String,Object>();
  11.     mMap.put("img", R.drawable.icon);
  12.     mMap.put("title1""标题");
  13.     mMap.put("title2""副标题");
  14.     mMap.put("time""2011-08-15 09:00");
  15.     mList.add(mMap);
  16. }  
  17. //创建适配器  
  18. SimpleAdapter mAdapter = new SimpleAdapter(this, mList, R.layout.item, mFrom, mTo);
  19. mListView.setAdapter(mAdapter);

这里要注意对应关系,Layout中的id,程序中对它的引用,Map中的数据。 

到这里已经实现了上面那张图的效果。但是程序需要一些交互操作,比如单击某一项,长按某一项,怎么办?

看下面:

添加点击事件:

Java代码  收藏代码
  1. mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {  
  2.     @Override  
  3.     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {  
  4.         @SuppressWarnings("unchecked")  
  5.         // 获取被点击的item所对应的数据
  6.         HashMap<String,Object> map = (HashMap<String, Object>) parent.getItemAtPosition(position);
  7.         //下面是你的其他事务逻辑  
  8.     }  
  9. });

这里可以通过position获取被点击的item所对应的Map数据,拿到这个数据了,还怕有什么功能实现不了吗?

举个最常见的例子,数据是从数据库里取的,每条数据有唯一的id,点了某一项之后,需要得到这个id进行数据操作,怎么办?很简单,在准备数据的时候,往Map中多添加一条数据,map.put("id",id),在上面的事件处理中,可以通过(Long) map.get("id")来获取id(此处假设id是long类型),取到id之后就可以进行数据库操作了。放心,添加的额外数据不会影响View的显示,因为有对应关系在。

长按事件和这个类似,无非是注册OnItemLongClickListener事件,在此就不列代码了。

还有最后一个问题,界面中每个item后面显示了一个单选框,明显是为批处理留的,该如何实现呢?

仔细想一下,会发现难点在于单选框状态的记录及获取。下面是我的方法:

在定义SimpleAdapter对象的时候,重写它的getView方法。如下:

Java代码  收藏代码
  1. mAdapter = new SimpleAdapter(this, pictureList, R.layout.picturelist, mFrom, mTo) {
  2.     @Override
  3.     public View getView(final int position, View convertView, ViewGroup parent) {
  4.         View view = super.getView(position, convertView, parent);
  5.         @SuppressWarnings("unchecked")
  6.         final HashMap<String,Object> map=(HashMap<String, Object>)this.getItem(position);  
  7.         //获取相应View中的Checkbox对象  
  8.         CheckBox checkBox = (CheckBox)view.findViewById(R.id.checked);  
  9.         checkBox.setChecked((Boolean) map.get("checked"));  
  10.         //添加单击事件,在map中记录状态  
  11.         checkBox.setOnClickListener(new View.OnClickListener() {  
  12.             @Override  
  13.             public void onClick(View view) {  
  14.                 map.put("checked", ((CheckBox)view).isChecked());  
  15.             }  
  16.         });  
  17.         return view;  
  18.     }  
  19. };  

在其他地方获取状态并处理:

Java代码  收藏代码
  1. //获取列表中的项目总数  
  2. int count = pictureListView.getCount();  
  3. Map<String, Object> map = null;  
  4. boolean isChecked;  
  5. long id;
  6. for (int i = 0; i < count; i++) {  
  7.     map = (Map<String, Object>) pictureListView.getItemAtPosition(i);  
  8.     isChecked = (Boolean) map.get("isChecked");  
  9.     if (isChecked) {  
  10.         id = (Long) map.get("id");  
  11.         //被选中的逻辑  
  12.     } else {  
  13.         id = (Long) map.get("id");  
  14.         //未被选中的逻辑  
  15.     }
  16. }  
  17. //如果操作过程中对列表内容进行了添加或删除,需要调用下面这个方法来更新视图  
  18. mAdapter.notifyDataSetChanged();  

还有一点忘了写了,demo中的图片是drawable里面的图片,如果map中只有图片的地址,如何把它转成drawable对象显示出来呢?我在这里也研究了好久,map中放入drawable对象传过去好像没用,不会显示,怎么办?好在前面有重写SimpleAdapter的getView方法。map中把图片地址放进去,在getView方法里面,把此地址转成drawable对象,然后设置给ImageView,大功告成!代码如下:

Java代码  收藏代码
  1. mAdapter = new SimpleAdapter(this, pictureList, R.layout.picturelist, mFrom, mTo) {
  2.     @Override    
  3.     public View getView(final int position, View convertView, ViewGroup parent) {
  4.         View view = super.getView(position, convertView, parent);  
  5.         @SuppressWarnings("unchecked")  
  6.         final HashMap<String,Object> map=(HashMap<String,Object>)this.getItem(position); 
  7.         ImageView imageView = (ImageView)view.findViewById(R.id.img);
  8.         FileInputStream fin;
  9.         try {  
  10.             if(map.get("img") == null){  
  11.                 throw new IOException();  
  12.             }  
  13.             fin = getApplicationContext().openFileInput((String) map.get("img"));  
  14.             imageView.setImageDrawable(Drawable.createFromStream(fin, "src"));  
  15.             fin.close();  
  16.         } catch (FileNotFoundException e) {  
  17.             imageView.setImageResource(R.drawable.default);  
  18.         } catch (IOException e) {  
  19.             imageView.setImageResource(R.drawable.default);  
  20.         }  
  21.         return view;  
  22.     }  
  23. };  

 好了,就到这里了。


AdapterView的使用:【在ListView中看到的AdapterView】

继承关系:
View<-ViewGroup<-AdapterView<-ListView,GridView,Spinner,Gallery
功能:
个Adapter对象作为一个AdapterView和View底层数据之间桥,提供对data Items的存取,同时负责针对每个Data如何渲染到对应的View中

1、数据库Cursor: SimpleCursorAdapter
结构:
SimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to)
功能:
将游标Cursor中的一行转换为容器控件的子容器。
2、String[]: ArrayAdapter
将字符串数组中的数据转换为容器控件的子容器。
3、List: SimpleAdapter
结构:
SimpleAdapter (Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to)
参数:
context:关联SimpleAdapter运行着的视图的上下文,一般而言也就是Activity。
data:一个Map的列表。在列表中的每个条目对应列表中的一行,应该包含所有在from中指定的条目。
resource :一个定义列表项目的视图布局的资源唯一标识。布局文件将至少应包含哪些在to中定义了的名称。
from:一个将被添加到Map上关联每一个项目的列名称的列表
to:应该在参数from显示列的视图。这些应该全是TextView。在列表中最初的N视图是从参数from中最初的N列获取的值。

 

使用AdapterView来绑定数据

AdapterView是一个ViewGroup子类, 它的子View是有一个Adapter决定的, 而该Adapter绑定某种类型的数据. AdapterView在你希望显示储存的数据(相对于资源字符串或者图片)时比较有用.
Gallery, ListView, 和 Spinner是AdapterView子类的例子, 你可以使用它们绑定特定类型的数据并按照一定方式来显示它们.
AdapterView对象有两个主要任务: 
    * 在布局中显示数据
    * 处理用户的选择
Filling the Layout with Data 为布局填充数据
将数据插入布局一般是通过将AdapterView类绑定到一个Adapter完成的. Adapter从一个外部资源获取数据(可能是代码直接提供,也可能是从设备上的一个数据库查到的数据组成的一个列表).
下列代码做了两件事情: 
   1. 使用一个已有的View创建了一个Spinner, 并将其绑定到一个新的ArrayAdapter, 后者从本地资源中读取一个颜色的数组.
   2. 从一个View创建另一个 Spinner对象并将它绑定到一个新的SimpleCursorAdapter, 后者将读取设备上的联系人名字.
// Get a Spinner and bind it to an ArrayAdapter that
// references a String array.
Spinner s1 = (Spinner) findViewById(R.id.spinner1);
ArrayAdapter adapter = ArrayAdapter.createFromResource(
    this, R.array.colors, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
s1.setAdapter(adapter);

// Load a Spinner and bind it to a data query.
private static String[] PROJECTION = new String[] {People._ID, People.NAME};

Spinner s2 = (Spinner) findViewById(R.id.spinner2);
Cursor cur = managedQuery(People.CONTENT_URI, PROJECTION, null, null);
    
SimpleCursorAdapter adapter2 = new SimpleCursorAdapter(this,
    android.R.layout.simple_spinner_item, // Use a template
                                          // that displays a
                                          // text view
    cur, // Give the cursor to the list adatper
    new String[] {People.NAME}, // Map the NAME column in the
                                         // people database to...
    new int[] {android.R.id.text1}); // The "text1" view defined in
                                     // the XML template
                                        
adapter2.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
s2.setAdapter(adapter2);

注意必须People._ID 列必须和CursorAdapter 一起使用, 否则你会得到异常.
如果在你的应用程序生命周期中, 你改变了你的Adapter管理的数据, 你应该调用notifyDataSetChanged(). 这将使附加的View刷新.
Handling User Selections 处理用户选择
使用AdapterView.OnItemClickListener来获取用户的选择.
// Create a message handling object as an anonymous class.
private OnItemClickListener mMessageClickedHandler = new OnItemClickListener() {
    public void onItemClick(AdapterView parent, View v, int position, long id) {
        // Display a messagebox.
        Toast.makeText(mContext,"You've got an event",Toast.LENGTH_SHORT).show();
    }
};

// Now hook into our object and set its onItemClickListener member
// to our class handler object.
mHistoryView = (ListView)findViewById(R.id.history);
mHistoryView.setOnItemClickListener(mMessageClickedHandler)

0 0
原创粉丝点击