ListView是Android开发中很常用的组件,上篇写到的TabHost的第三个Tab就是一个ListView,里面填充的是从数据库中得到的一长串时间、体重数据,每一行一条数据。
一般来说,列表的显示需要三个元素:
1.视图 用来展示列表的View。
2.适配器 用来把数据映射到ListView上的中介。分为三种:ArrayAdapter,SimpleAdapter和 SimpleCursorAdapter。
3.数据 具体的将被映射的字符串,图片,或者基本组件。
这里我的主Activity已经继承自TabActivity,而很多ListView例子都是继承自ListActivity。一女不能事二夫,java也不支持多继承(extends),必须自己来使用Widget组件ListView。实际上ListActivity和一般的Activity没什么区别,自己写写Adapter、listener实现ListActivity给我们简化的一些操作就行了。
(一) 在main.xml中要显示列表的地方加入ListView,这里的id可随便写,因为不继承ListActivity,不必写成android:id="@id/android:list"这种奇特的样子。.
<LinearLayout
android:id="@+id/linearLayout3"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ListView
android:id="@+id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>
(二) 新增一个vlist.xml,里面记录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/imgtest"
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="Remove"
android:focusable="false"
android:layout_gravity="bottom|right" />
</LinearLayout>
这里将button设置为没有焦点是因为不这么做的话,运行时你会发现listView的每一行没有焦点了,这是因为Button抢夺了listView的焦点。
(三)主Activity:
加成员变量:
protected ListView lv;
private List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
在onCreate中加入:
lv=(ListView)findViewById(R.id.list);
generateData();//从数据库中读数据并加入到list变量中
MyAdapter adapter=new MyAdapter(this,list);//自己写的Adapter,响应删除按钮的点击事件
lv.setAdapter(adapter);
其中generateData方法如下:从数据库读出数据,填充到HashMap中,每个map包含四个key(id,title,info,img),然后将该map加入到 list中。
private void generateData() {
db = sqlHelper.getWritableDatabase();
Cursor cursor = db.rawQuery("select id,weight,datetime(timestamp,'localtime') from tb3",null);
int index=0;//just for adding different img
for (cursor.moveToFirst();!(cursor.isAfterLast());cursor.moveToNext())
{
index++;
Map<String, Object> map = new HashMap<String, Object>();
String myID=cursor.getString(cursor.getColumnIndex("id"));
String myDate = cursor.getString(cursor.getColumnIndex("datetime(timestamp,'localtime')"));
double myWeight=cursor.getDouble(cursor.getColumnIndex("weight"));
map.put("id", myID);
map.put("title", "Record at:"+myDate);
map.put("info", "Weight:"+myWeight);
switch(index%3){
case 1:
map.put("img", R.drawable.i1);break;
case 2:
map.put("img",R.drawable.i2);break;
default:
map.put("img",R.drawable.i3);break;
}
list.add(map);
}
db.close();
}
(四) 自定义Adapter类。这个类颇费一番心机,有关难点请看注释:
public class MyAdapter extends BaseAdapter {
private LayoutInflater mInflater;
private Context context;
private List<Map<String, Object>> mData;
public MyAdapter(Context context)
{
this.context=context;
this.mInflater=LayoutInflater.from(context);
}
public MyAdapter(Context context,List<Map<String, Object>> list)
{
this.mInflater=LayoutInflater.from(context);
this.mData=list;//传递要显示的列表进来
this.context=context;
}
@Override
public int getCount() {
return mData.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
//View中的setTag(Object)表示给View添加一个格外的数据,以后可以用getTag()将这个数据取出来。
@Override
public View getView(int position, View convertView, ViewGroup parent) {
/*Adapter的作用就是ListView界面与数据之间的桥梁,当列表里的每一项显示到页面时,
*都会调用Adapter的getView方法返回一个View。如果每个view都用inflate的话,列表项数一多就会占用极大的系统资源。
* View中的setTag(Object)表示给View添加一个格外的数据(ViewHolder类),以后可以用getTag()将这个数据取出来。
* 这样做可以优化性能!*/
ViewHolder holder = null;
if (convertView == null) {
holder=new ViewHolder();
convertView = mInflater.inflate(R.layout.vlist, null);
holder.img = (ImageView)convertView.findViewById(R.id.imgtest);
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"));
/*为什么还要加个StringHolder呢?将数据依附到button中,向button的OnClicklistener传参!*/
StringHolder strholder=new StringHolder();
strholder.title=(String)mData.get(position).get("title");
strholder.info=(String)mData.get(position).get("info");
strholder.id=(String) mData.get(position).get("id");
holder.viewBtn.setTag(strholder);//setTag
holder.viewBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
/*尽管在代码中相隔这么近,但是这里是button的匿名响应函数的世界,
* 咫尺天涯,title、info这些参数可望而不可及。好在我们还有setTag和getTag!*/
StringHolder holder=(StringHolder) v.getTag();
final String strDataID=holder.id;//为什么是final,让后面的onclickListner认识啊!
new AlertDialog.Builder(context)
.setTitle("真的要删除"+holder.title+"吗?")
.setMessage(holder.info)
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
})
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
DBHelper sqlHelper;
SQLiteDatabase db;
sqlHelper = new DBHelper(context, "test.db", null, 2);
db = sqlHelper.getWritableDatabase();
//这里要获取id的值也是个问题,解决方法就是final
db.delete("tb3", "id=?", new String[]{strDataID});
db.close();
}
})
.show();
}
});
return convertView;
}
public final class ViewHolder{
public ImageView img;
public TextView title;
public TextView info;
public Button viewBtn;
}
public final class StringHolder{
public String title;
public String info;
public String id;
}
}