​http://www.iteye.com/topic/540423​

ListView是比较常用的控件,但一直都觉得创建ListView步骤有点繁琐,故在此总结一下,方便查阅。

程序效果是实现一个ListView,ListView里面有标题,内容和图片,并加入点击和长按响应。

首先在xml里面定义一个ListView

1. <?xml version="1.0" encoding="utf-8"?>
2. <LinearLayout
3. android:id="@+id/LinearLayout01"
4. android:layout_width="fill_parent"
5. android:layout_height="fill_parent"
6. xmlns:android="http://schemas.android.com/apk/res/android">
7. <ListView android:layout_width="wrap_content"
8. android:layout_height="wrap_content"
9. android:id="@+id/ListView01"
10. />
11. </LinearLayout>

定义ListView每个条目的Layout,用RelativeLayout实现:​


1. <?xml version="1.0" encoding="utf-8"?>
2. <RelativeLayout
3. android:id="@+id/RelativeLayout01"
4. android:layout_width="fill_parent"
5. xmlns:android="http://schemas.android.com/apk/res/android"
6. android:layout_height="wrap_content"
7. android:paddingBottom="4dip"
8. android:paddingLeft="12dip"
9. android:paddingRight="12dip">
10. <ImageView
11. android:paddingTop="12dip"
12. android:layout_alignParentRight="true"
13. android:layout_width="wrap_content"
14. android:layout_height="wrap_content"
15. android:id="@+id/ItemImage"
16. />
17. <TextView
18. android:text="TextView01"
19. android:layout_height="wrap_content"
20. android:textSize="20dip"
21. android:layout_width="fill_parent"
22. android:id="@+id/ItemTitle"
23. />
24. <TextView
25. android:text="TextView02"
26. android:layout_height="wrap_content"
27. android:layout_width="fill_parent"
28. android:layout_below="@+id/ItemTitle"
29. android:id="@+id/ItemText"
30. />
31. </RelativeLayout>


 

 最后在Activity里面调用和加入Listener,具体见注释:

 

package com.ray.test;

import java.util.ArrayList;
import java.util.HashMap;

import android.app.Activity;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.MenuItem;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View.OnCreateContextMenuListener;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.AdapterView.OnItemClickListener;

public class TestListView extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//绑定Layout里面的ListView
ListView list = (ListView) findViewById(R.id.ListView01);

//生成动态数组,加入数据
ArrayList<HashMap<String, Object>> listItem = new ArrayList<HashMap<String, Object>>();
for(int i=0;i<10;i++)
{
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("ItemImage", R.drawable.checked);//图像资源的ID
map.put("ItemTitle", "Level "+i);
map.put("ItemText", "Finished in 1 Min 54 Secs, 70 Moves! ");
listItem.add(map);
}
//生成适配器的Item和动态数组对应的元素
SimpleAdapter listItemAdapter = new SimpleAdapter(this,listItem,//数据源
R.layout.list_items,//ListItem的XML实现
//动态数组与ImageItem对应的子项
new String[] {"ItemImage","ItemTitle", "ItemText"},
//ImageItem的XML文件里面的一个ImageView,两个TextView ID
new int[] {R.id.ItemImage,R.id.ItemTitle,R.id.ItemText}
);

//添加并且显示
list.setAdapter(listItemAdapter);

//添加点击
list.setOnItemClickListener(new OnItemClickListener() {

@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
setTitle("点击第"+arg2+"个项目");
}
});

//添加长按点击
list.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {

@Override
public void onCreateContextMenu(ContextMenu menu, View v,ContextMenuInfo menuInfo) {
menu.setHeaderTitle("长按菜单-ContextMenu");
menu.add(0, 0, 0, "弹出长按菜单0");
menu.add(0, 1, 0, "弹出长按菜单1");
}
});
}

//长按菜单响应函数
@Override
public boolean onContextItemSelected(MenuItem item) {
setTitle("点击了长按菜单里面的第"+item.getItemId()+"个项目");
return super.onContextItemSelected(item);
}
}

 

写道



ListView是Android开发中非常常用的组件,ListView可以用来显示一个列表,我们可以对这个列表操作,比如点击列表要做什么等等。这篇文章主要通过一个示例来展示ListView的用法。


一、  不使用 xml 布局文件创建一个 ListView

  1. 创建一个名称为 HelloListView 的 Android 工程,可以参见 ​​ Android教程之三:第一个Android应用,HelloWorld​​  。
  2. 要使用 ListView ,需要让你的 Activity 继承于 ListActivity ,这个和以前的有区别,以前的都是继承 Activity ,该 ListActivity 继承 Activity ,扩展了很多常用的用于操作 ListView 的方法,使用很方便。 
  3. 现修改 HelloListView 类如下 : 
1. public class HelloListView extends ListActivity {  
2. /** Called when the activity is first created. */
3. @Override
4. public void onCreate(Bundle savedInstanceState) {
5. super.onCreate(savedInstanceState);
6. //setContentView(R.layout.main);
7. //设置一个Adapter
8. setListAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,COUNTRIES));
9. }
10. //数据数据
11. private static final String[] COUNTRIES=new String[]{"中国","俄罗斯","英国","法国"};
12. }


  1. 运行程序效果如下:

     看到了吧,我们的数据已经通过列表的形式显示了出来!!!

这里主要的是使用了一个 Adapter— 适配器,你可以把他看成是 ListView 的数据源, ListView 要展示的数据都是已 Adapter 的形势传递给 ListView 的。这个 Adapter 很重要, Android 的用于传给集合控件( ListView,Spinner,GridView 等)的数据都是以 Adapter 的形势,这样的好处就是只要掌握了 Adapter ,就可以很随意的给这些集合控制传递数据,因为他们使用的都是 Adapter 。适配器适配器关键就是适配,只需公布一个 Adapter ,就全搞定了。 Android 已经给我们实现了一些常用的适配器,如刚刚使用的数组适配器,还有简单适配器等 , 如果这些不能满足,我们还可以通过自定义适配器来实现自己的适配器。其实一种适配器就对应了一个集合控件中的一个元素的布局展示。 

二:  使用 xml 来自定义 ListView

  1. 上个例子我们并没有使用在 main.xml 中定义一个 ListView 的形势来布局 ListView ,而是使用的 ListActivity 中默认的 ListView 来演示的。 
  2. 下面就使用我们在 main.xml 中自定义的 ListView, 这样我们可以很方便的控制 ListView 展示的布局,大小,背景色等属性。当然上个例子中我们一样可以通过 getListView 获取 ListView 后使用它的方法来改变布局、大小和背景色等。 
  3. 修改 main.xml 为: 
1. <?xml version="1.0" encoding="utf-8"?>  
2. <ListView xmlns:android="http://schemas.android.com/apk/res/android"
3. android:id="@android:id/list"
4. android:layout_width="fill_parent"
5. android:layout_height="fill_parent"
6. android:background="#FF0000FF"
7. >
8. </ListView>
  1. 修改 HelloListView 类为: 
4.    
1. public class HelloListView extends ListActivity {
2. /** Called when the activity is first created. */
3. @Override
4. public void onCreate(Bundle savedInstanceState) {
5. super.onCreate(savedInstanceState);
6. setContentView(R.layout.main);
7. //设置一个Adapter
8. setListAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,COUNTRIES));
9. }
10. //数据数据
11. private static final String[] COUNTRIES=new String[]{"中国","俄罗斯","英国","法国"};
12. }


  1.  比上个例子只是多了 setContentView(R.layout. main ); 是为了让 Android 识别我们定义的 ListView 。 
  2. 运行效果图: 

     背景已经变成了蓝色,说明我们在xml中定义的ListView起作用了。

三: 自定义要展示的元素

  1. 前面的两个例子都是展示一行文字,如果我们想图文混排怎么做呢,比如前面是文字,后面是图片。要实现这种功能就需要我们自定义 Adapter 啦。 
  2. 新建布局文件 item.xml, 内容如下: 
1. <?xml version="1.0" encoding="utf-8"?>  
2. <RelativeLayout
3. xmlns:android="http://schemas.android.com/apk/res/android"
4. android:layout_width="fill_parent"
5. android:layout_height="wrap_content">
6. <TextView
7. android:id="@+id/text"
8. android:layout_alignParentLeft="true"
9. android:layout_width="wrap_content"
10. android:layout_height="wrap_content"/>
11. <ImageView
12. android:id="@+id/image"
13. android:layout_alignParentRight="true"
14. android:layout_width="wrap_content"
15. android:layout_height="wrap_content"/>
16. </RelativeLayout>


这里主要定义一个 TextView 和一个 ImageView ,用于显示列表每一行的文本和图片 

  1. 修改 HelloListView 类如下: 

1. public class HelloListView extends ListActivity {  
2. /** Called when the activity is first created. */
3. @Override
4. public void onCreate(Bundle savedInstanceState) {
5. super.onCreate(savedInstanceState);
6. setContentView(R.layout.main);
7. //设置一个Adapter,使用自定义的Adapter
8. setListAdapter(new TextImageAdapter(this));
9. }
10. /**
11. * 自定义视图
12. * @author 飞雪无情
13. *
14. */
15. private class TextImageAdapter extends BaseAdapter{
16. private Context mContext;
17. public TextImageAdapter(Context context) {
18. this.mContext=context;
19. }
20. /**
21. * 元素的个数
22. */
23. public int getCount() {
24. return texts.length;
25. }
26.
27. public Object getItem(int position) {
28. return null;
29. }
30.
31. public long getItemId(int position) {
32. return 0;
33. }
34. //用以生成在ListView中展示的一个个元素View
35. public View getView(int position, View convertView, ViewGroup parent) {
36. //优化ListView
37. if(convertView==null){
38. convertView=LayoutInflater.from(mContext).inflate(R.layout.item, null);
39. ItemViewCache viewCache=new ItemViewCache();
40. viewCache.mTextView=(TextView)convertView.findViewById(R.id.text);
41. viewCache.mImageView=(ImageView)convertView.findViewById(R.id.image);
42. convertView.setTag(viewCache);
43. }
44. ItemViewCache cache=(ItemViewCache)convertView.getTag();
45. //设置文本和图片,然后返回这个View,用于ListView的Item的展示
46. cache.mTextView.setText(texts[position]);
47. cache.mImageView.setImageResource(images[position]);
48. return convertView;
49. }
50. }
51. //元素的缓冲类,用于优化ListView
52. private static class ItemViewCache{
53. public TextView mTextView;
54. public ImageView mImageView;
55. }
56. //展示的文字
57. private String[] texts=new String[]{"天气","我团","背景"};
58. //展示的图片
59. private int[] images=new int[]{R.drawable.img1,R.drawable.img2,R.drawable.img3};
60. }


  1. 这里的主要地方是自定义了一个 Adapter ,我们只需要继承 BaseAdapter 即可, BaseAdapter 已经实现了 Adapter 的大部分方法,我们继承后只需要实现部分的方法即可。必须实现的就是 getCount 和 getView 方法,前一个是返回 ListView 中有多少个元素,后一个是生成要展示的 View 。 ListView 在每添加一个 View 是就会调用 Adapter 的 getView 方法,所以我们有必要对这个方法做优化,例子中就做了部分的优化,一般面试的时候会被问到 ListView 优化,回答例子中的这些代码就差不多了。 
  2. 运行,我们会看到效果如图: 

四、ListView 列表中的元素的单击事件响应

  1. 如果我们要想单击一个  ListView 的元素使其作出相应的响应怎么办呢?比如弹出什么,打开什么,展示什么等等,那么我们只需要实现单击事件的函数既可。 
  2. 要实现 ListView 的单击事件有两种方法,一个是使用 getListView().setOnClickListener(l ); 设置,这个和平时我们用的控件设置是一样的,不做介绍,下面介绍第二个,就是重写 ListActivity 的 onListItemClick 方法,其实这个的最后处理也是 ListView 的 setOnClickListener 进行监听调用的。 
  3. 在 HelloListView 类中增加如下代码: 

1. @Override  
2. protected void onListItemClick(ListView l, View v, int position, long id) {
3. Toast.makeText(this, "你单击了"+texts[position], Toast.LENGTH_SHORT).show();
  1. 运行单击其中的一行效果如下图: 

五、小结

到这里ListView应该算是会使用了,起码常用的功能会的,当然还有很多没有说到的,比如ListView的分割部分,headView和footView以及ListView的分页等等,这些就需要我们自己下去好好摸索了。



本示例说明:

1.自定义listview条目样式,自定义listview显示列数的多少,灵活与数据库中字段绑定.

2.实现对DB的增删改查,并且操作后listview自动刷新.

3.响应用户操作点击事件,示例中展示单击时取出主键Id和其他内容.

4.响应用户操作长按事件,示例中展示长按时根据主键Id来编辑和删除数据.

5.表现层与数据处理层分开,不依赖于cursor(使用cursor不易表现和业务分离),支持接口编程.

6.使用数据库处理框架AHibernate灵活操作sqlite数据库,详见: javascript:void(0)


本示例效果图:

Android ListView常用用法(结合长按、数据库等)_xml_05

Android ListView常用用法(结合长按、数据库等)_android_06

Android ListView常用用法(结合长按、数据库等)_android_07

Android ListView常用用法(结合长按、数据库等)_xml_08


列出主要代码:

1.list.xml:

<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/child"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#E3D25E"
android:orientation="horizontal" >

<!-- 若想隐藏id加入此属性: android:visibility="gone",这样做有点类似于Html中hidden域 -->

<TextView
android:id="@+id/idTo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ff0000" />

<TextView
android:id="@+id/nameTo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="5px"
android:paddingLeft="50px"
android:paddingTop="5px"
android:text="No data"
android:textColor="#0000ff"
android:textSize="20sp" />

<TextView
android:id="@+id/ageTo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="5px"
android:paddingLeft="50px"
android:paddingTop="5px"
android:text="No data"
android:textColor="#00ff00"
android:textSize="20sp" />

</LinearLayout>

 

2.MainActivity.java:

package com.tgb.lk.listview;

import java.util.List;
import java.util.Map;

import com.tgb.lk.demo.dao.StudentDao;
import com.tgb.lk.demo.dao.impl.StudentDaoImpl;
import com.tgb.lk.demo.model.Student;

import com.tgb.lk.listview.R;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.ContextMenu;
import android.view.MenuItem;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
/**
* 欢迎访问我的博客进行对代码交流: http://blog.csdn.net/lk_blog
* 数据库处理使用AHibernate框架,详见:javascript:void(0)
* @author likun
*/
public class MainActivity extends Activity {
private static final int ITEM_MODIFY = 1;
private static final int ITEM_DELETE = 2;

// 定义接口
private StudentDao dao = null;
private ListView lv = null;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

// 添加
Button btnAdd = (Button) findViewById(R.id.btnAdd);
btnAdd.setOnClickListener(listener);
// 显示前3条数据
Button btnShow = (Button) findViewById(R.id.btnShow);
btnShow.setOnClickListener(listener);
// 删除数据
Button btnClear = (Button) findViewById(R.id.btnClear);
btnClear.setOnClickListener(listener);

lv = (ListView) findViewById(R.id.lvStudent);
// 设置在条目上单击监听器
lv.setOnItemClickListener(itemListener);
// 设置长按事件
registerForContextMenu(lv);

// 显示所有数据
showData(-1);
}

// 显示数据,num小于等于0时显示所有数据,num大于0时显示前N条.
private void showData(int num) {
dao = (dao == null ? new StudentDaoImpl(this) : dao);
List<Map<String, String>> data = null;
if (num <= 0) { // 显示所有学生,调用dao层接口
data = dao.queryAllStudent();
} else {// 显示前N个学生,调用dao层接口
data = dao.queryTopN(num);
}
SimpleAdapter adapter = buildListAdapter(this, data);
lv.setAdapter(adapter);

}

// 构建adapter.
public SimpleAdapter buildListAdapter(Context context,
List<Map<String, String>> data) {
SimpleAdapter adapter = new SimpleAdapter(context, data, R.layout.list,
new String[] { "_id", "name", "age" }, new int[] { R.id.idTo,
R.id.nameTo, R.id.ageTo });
return adapter;
}

// 初始化数据
OnClickListener listener = new OnClickListener() {
@Override
public void onClick(View v) {
dao = (dao == null ? new StudentDaoImpl(MainActivity.this) : dao);
switch (v.getId()) {
case R.id.btnAdd:
// 添加学生
Student student1 = new Student();
student1.setName("lk");
student1.setAge(26);
dao.insert(student1);

Student student2 = new Student();
student2.setName("cls");
student2.setAge(26);
dao.insert(student2);

Student student3 = new Student();
student3.setName("lb");
student3.setAge(27);
dao.insert(student3);
showData(-1);

break;
case R.id.btnShow:
// 显示前3条数据
showData(3);
break;
case R.id.btnClear:
// 删除所有数据
dao.deleteData();

// 显示所有数据
showData(-1);
break;
default:
break;
}

}
};

// 条目上单击处理方法.
OnItemClickListener itemListener = new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
// 这里的view是我们在list.xml中定义的LinearLayout对象.
// 所以可以通过findViewById方法可以找到list.xml中定义的它的子对象,如下:
TextView stuId = (TextView) view.findViewById(R.id.idTo);
TextView stuName = (TextView) view.findViewById(R.id.nameTo);
TextView stuAge = (TextView) view.findViewById(R.id.ageTo);

toastShow("学号:" + stuId.getText().toString() + "; 姓名:"
+ stuName.getText().toString() + "; 年龄:"
+ stuAge.getText().toString());
}
};

// 封装Toast,一方面调用简单,另一方面调整显示时间只要改此一个地方即可.
public void toastShow(String text) {
Toast.makeText(MainActivity.this, text, 1000).show();
}

// 长按时显示的菜单
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
menu.setHeaderTitle("请选择操作");
menu.add(0, ITEM_MODIFY, 0, "编辑");
menu.add(0, ITEM_DELETE, 1, "删除");
}

// 响应编辑和删除事件处理
public boolean onContextItemSelected(MenuItem item) {
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
.getMenuInfo();
// info.targetView得到list.xml中的LinearLayout对象.
String stuId = ((TextView) info.targetView.findViewById(R.id.idTo))
.getText().toString();
if (!TextUtils.isEmpty(stuId)) {
int id = Integer.parseInt(stuId);
dao = (dao == null ? new StudentDaoImpl(this) : dao);
switch (item.getItemId()) {
case ITEM_MODIFY:
// 编辑数据
toastShow("编辑" + stuId);
// 此方法定义在AHibernate中.更多使用示例见javascript:void(0)
Student student = dao.get(id);
student.setName("李坤");
student.setAge(26);
dao.update(student); // 此方法定义在AHibernate中.
break;
case ITEM_DELETE:
// 删除数据
toastShow("删除" + stuId);
dao.delete(id);// 此方法定义在AHibernate中.
break;
default:
break;
}
}
showData(-1);
return false;
}

}

3.数据库处理层:StudentDaoImpl.java:

package com.tgb.lk.demo.dao.impl;

import java.util.List;
import java.util.Map;

import com.tgb.lk.ahibernate.dao.impl.BaseDaoImpl;
import com.tgb.lk.demo.dao.StudentDao;
import com.tgb.lk.demo.model.Student;
import com.tgb.lk.demo.util.DBHelper;
import android.content.Context;

//本文数据库处理引用jar包AHibernate处理.
//AHibernate的详细使用教程示例地址: javascript:void(0)
//AHibernate源码交流地址: http://blog.csdn.net/lk_blog/article/details/7456125
//AHibernate jar包下载及源代码下载地址: http://download.csdn.net/detail/lk_blog/4222048
public class StudentDaoImpl extends BaseDaoImpl<Student> implements StudentDao {
public StudentDaoImpl(Context context) {
super(new DBHelper(context));
}

// 返回一个List,List中的对象是以sql中的列的小写形式为key的Map.(本例中 _id,name,age为key)
public List<Map<String, String>> queryAllStudent() {
String sql = "select _id, name,age from t_student";
return super.query2MapList(sql, null);
}

// 返回一个List,List中的对象是以sql中的列的小写形式为key的Map.(本例中 _id,name,age为key)
public List<Map<String, String>> queryTopN(int num) {
String sql = "select _id, name,age from t_student limit ?";
return super.query2MapList(sql, new String[] { String.valueOf(num) });
}

public void deleteData() {
String sql = "delete from t_student";
super.execSql(sql, null);
}
}

最后,希望大家不吝赐教,对本文不足之处进行批评指正.