接着上一节,上一节讲的是通过ArrayAdapter、SimpleAdapter给ListView绑定数据,它们的缺点就是在每一个item里面如果有按钮控件的话,点击是不管用的。这个时候我们就要用BaseAdapter。
这一节主要学习BaseAdapter,最后还会有使用继承ListActivity代替Activity的方法。
BaseAdapter是一个抽象类,要使用就必须要写一个类继承它,并实现它的方法。其中最重要的是getView方法。
这次我要实现的是在ListView中的每一行放上一个TextView和一个ImageButton,点击ImageButton会Toast出来点击的是哪一行。
主布局文件里面只有一个ListView控件
1 xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="fill_parent"
4 android:layout_height="fill_parent"
5 android:orientation="vertical" >
6
7 <ListView
8 android:id="@+id/listView1"
9 android:layout_width="fill_parent"
10 android:layout_height="wrap_content" >
11 ListView>
12 LinearLayout>
每一列要显示的内容,新建一个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"
4 android:layout_height="fill_parent"
5 android:orientation="horizontal"
6 android:descendantFocusability="blocksDescendants" >
7
8 <TextView
9 android:id="@+id/tvText"
10 android:layout_width="wrap_content"
11 android:layout_height="fill_parent"
12 android:gravity="left|center_vertical"
13 android:textSize="30sp" />
14
15
16 <ImageButton
17 android:id="@+id/ibView"
18 android:layout_width="wrap_content"
19 android:layout_height="wrap_content"
20 android:layout_alignParentRight="true"
21 android:layout_alignParentTop="true"
22 android:focusable="false"
23 android:src="@android:drawable/ic_menu_view"
24 android:background="#e0000000" />
25
26 RelativeLayout>
这个布局文件里面要注意的是android:descendantFocusability="blocksDescendants"和android:focusable="false",设置这两项以后ListView的item才可以获得焦点,否则焦点会再ImageButton上面。
实现过程比较复杂,定义一个ViewHolder来存放控件
//定义一个类来存放控件,对应每一行的布局文件中的控件
class ViewHolder{
public TextView itemtext;
public ImageButton itemview;
}
然后声明一个类来继承BaseAdapter,代码里面按照我的理解做了说明
1 //声明一个类来继承BaseAdapter
2 class myAdapter extends BaseAdapter{
3 //定义一个LayoutInflater来导入资源文件用
4 LayoutInflater inflater;
5 //用来接收要绑定的数据
6 ArrayList> arrayList;
7 //要绑定的资源文件id
8 int resID;
9 public myAdapter(Context context,ArrayList> arrayList2,int resId){
10 this.inflater=LayoutInflater.from(context);
11 this.arrayList=arrayList2;
12 this.resID=resId;
13 }
14 //绑定的数据的长度,也就是ListView项的个数
15 @Override
16 public int getCount() {
17 // TODO Auto-generated method stub
18 return this.arrayList.size();
19 }
20
21 @Override
22 public Object getItem(int position) {
23 // TODO Auto-generated method stub
24 return null;
25 }
26
27 @Override
28 public long getItemId(int position) {
29 // TODO Auto-generated method stub
30 return 0;
31 }
32 //重要的方法
33 @Override
34 public View getView(final int position, View convertView, ViewGroup parent) {
35 //创建一个ViewHolder来盛放控件
36 ViewHolder vHolder;
37 //通过判断convertView是否为空来取得ViewHolder对象
38 //这个convertView就是ListView的一行
39 if (convertView==null) {
40 //如果为null则从布局文件中导入
41 convertView=inflater.inflate(this.resID, null);
42 vHolder=new ViewHolder();
43 vHolder.itemtext=(TextView)convertView.findViewById(R.id.tvText);
44 vHolder.itemview=(ImageButton)convertView.findViewById(R.id.ibView);
45 //setTag方法用来设置与视图关联的标签,我的理解就是把和它相关的ViewHolder存储起来,到用的时候再拿出来
46 convertView.setTag(vHolder);
47 } else {
48 //如果不为null就直接通过getTag取出来
49 vHolder=(ViewHolder)convertView.getTag();
50 }
51 //然后给ViewHolder对象的每一项赋值
52 vHolder.itemtext.setText(this.arrayList.get(position).get("text").toString());
53 //添加按钮的点击事件
54 vHolder.itemview.setOnClickListener(new OnClickListener(){
55
56 @Override
57 public void onClick(View v) {
58 Toast.makeText(ListView_BaseAdapter2.this, "ImageButton "+(position+1)+"clicked!", Toast.LENGTH_SHORT).show();
59 }
60 });
61 return convertView;
62 }
63 }
这里定义一个方法来生成数据,我测试的是20000行
1 //定义一个生成数据的方法,因为HashMap的键对应的值可能是String或者是资源的ID,所以这里用的是HashMap
2 private ArrayList> getData() {
3 ArrayList> aList=new ArrayList >();
4 for (int i = 0; i < 20000; i++) {
5 HashMapmap=new HashMap ();
6 map.put("text", "第"+(i+1)+"行");
7 aList.add(map);
8 }
9 return aList;
10 }
最后在ListView上面绑定数据
1 //获取ListView对象
2 lView=(ListView)findViewById(R.id.listView1);
3 //使用创建的adatper对象绑定数据
4 myAdapter adapter=new myAdapter(ListView_BaseAdapter2.this, getData(), R.layout.item);
5 lView.setAdapter(adapter);
这样就实现了每一行的ImageButton可点击,弹出Toast消息,显示所在行。测试的效果还算可以,2000行数据在我的V880上面平均是2.5秒的时间,打开以后滑动十分流畅。
下面是本次的完整代码
1 package com.yyj.ListView_BaseAdapter;
2
3 import java.util.ArrayList;
4 import java.util.HashMap;
5
6 import android.app.Activity;
7 import android.content.Context;
8 import android.os.Bundle;
9 import android.view.LayoutInflater;
10 import android.view.View;
11 import android.view.View.OnClickListener;
12 import android.view.ViewGroup;
13 import android.widget.BaseAdapter;
14 import android.widget.ImageButton;
15 import android.widget.ListView;
16 import android.widget.TextView;
17 import android.widget.Toast;
18
19 public class ListView_BaseAdapter2 extends Activity {
20 ListView lView;
21 @Override
22 protected void onCreate(Bundle savedInstanceState) {
23 super.onCreate(savedInstanceState);
24 setContentView(R.layout.main);
25 //获取ListView对象
26 lView=(ListView)findViewById(R.id.listView1);
27 //使用创建的adatper对象绑定数据
28 myAdapter adapter=new myAdapter(ListView_BaseAdapter2.this, getData(), R.layout.item);
29 lView.setAdapter(adapter);
30 }
31 //定义一个生成数据的方法,因为HashMap的键对应的值可能是String或者是资源的ID,所以这里用的是HashMap
32 private ArrayList> getData() {
33 ArrayList> aList=new ArrayList >();
34 for (int i = 0; i < 20000; i++) {
35 HashMapmap=new HashMap ();
36 map.put("text", "第"+(i+1)+"行");
37 aList.add(map);
38 }
39 return aList;
40 }
41 //定义一个类来存放控件,对应每一行的布局文件中的控件
42 class ViewHolder{
43 public TextView itemtext;
44 public ImageButton itemview;
45 }
46 //声明一个类来继承BaseAdapter
47 class myAdapter extends BaseAdapter{
48 //定义一个LayoutInflater来导入资源文件用
49 LayoutInflater inflater;
50 //用来接收要绑定的数据
51 ArrayList> arrayList;
52 //要绑定的资源文件id
53 int resID;
54 public myAdapter(Context context,ArrayList> arrayList2,int resId){
55 this.inflater=LayoutInflater.from(context);
56 this.arrayList=arrayList2;
57 this.resID=resId;
58 }
59 //绑定的数据的长度,也就是ListView项的个数
60 @Override
61 public int getCount() {
62 // TODO Auto-generated method stub
63 return this.arrayList.size();
64 }
65
66 @Override
67 public Object getItem(int position) {
68 // TODO Auto-generated method stub
69 return null;
70 }
71
72 @Override
73 public long getItemId(int position) {
74 // TODO Auto-generated method stub
75 return 0;
76 }
77 //重要的方法
78 @Override
79 public View getView(final int position, View convertView, ViewGroup parent) {
80 //创建一个ViewHolder来盛放控件
81 ViewHolder vHolder;
82 //通过判断convertView是否为空来取得ViewHolder对象
83 //这个convertView就是ListView的一行
84 if (convertView==null) {
85 //如果为null则从布局文件中导入
86 convertView=inflater.inflate(this.resID, null);
87 vHolder=new ViewHolder();
88 vHolder.itemtext=(TextView)convertView.findViewById(R.id.tvText);
89 vHolder.itemview=(ImageButton)convertView.findViewById(R.id.ibView);
90 //setTag方法用来设置与视图关联的标签,我的理解就是把和它相关的ViewHolder存储起来,到用的时候再拿出来
91 convertView.setTag(vHolder);
92 } else {
93 //如果不为null就直接通过getTag取出来
94 vHolder=(ViewHolder)convertView.getTag();
95 }
96 //然后给ViewHolder对象的每一项赋值
97 vHolder.itemtext.setText(this.arrayList.get(position).get("text").toString());
98 //添加按钮的点击事件
99 vHolder.itemview.setOnClickListener(new OnClickListener(){
100
101 @Override
102 public void onClick(View v) {
103 Toast.makeText(ListView_BaseAdapter2.this, "ImageButton "+(position+1)+"clicked!", Toast.LENGTH_SHORT).show();
104 }
105 });
106 return convertView;
107 }
108 }
109 }
效果图:
最后附上源文件:ListView_BaseAdapter.zip
下面在简单的说一下,在主布局文件中只有一个ListView的时候,我们可以使用ListActivity,ListActivity继承自Activity类,默认绑定了一个ListView,并提供一些处理ListView的操作。
直接贴上代码,里面要注意的地方已经注释上了
main.xml
1 xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="fill_parent"
4 android:layout_height="fill_parent"
5 android:orientation="vertical" >
6
7
8 <ListView
9 android:id="@+id/android:list"
10 android:layout_width="fill_parent"
11 android:layout_height="wrap_content"
12 >ListView>
13 LinearLayout>
user.xml
1 xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="match_parent"
4 android:layout_height="50dp"
5 android:orientation="horizontal" >
6
7 <TextView
8 android:id="@+id/uname"
9 android:layout_width="fill_parent"
10 android:layout_height="fill_parent"
11 android:gravity="center"
12 android:layout_weight="1"/>
13 <TextView
14 android:id="@+id/uage"
15 android:layout_width="fill_parent"
16 android:layout_height="fill_parent"
17 android:gravity="center"
18 android:layout_weight="1"/>
19 LinearLayout>
ListViewTestActivity.java
1 package com.yyj.ListViewTest;
2
3 import java.util.ArrayList;
4 import java.util.HashMap;
5
6 import android.app.ListActivity;
7 import android.os.Bundle;
8 import android.view.View;
9 import android.widget.ListView;
10 import android.widget.SimpleAdapter;
11 import android.widget.TextView;
12 import android.widget.Toast;
13
14 //注意,这里继承的是ListActivity,不是Activity
15 public class ListViewTestActivity extends ListActivity {
16 /** Called when the activity is first created. */
17 @Override
18 public void onCreate(Bundle savedInstanceState) {
19 super.onCreate(savedInstanceState);
20 setContentView(R.layout.main);
21
22 ArrayList> arrayList=new ArrayList >();
23 HashMapuser1=new HashMap ();
24 user1.put("username", "小明");
25 user1.put("userage", 24);
26 HashMapuser2=new HashMap ();
27 user2.put("username", "小红");
28 user2.put("userage", 22);
29 HashMapuser3=new HashMap ();
30 user3.put("username", "小丽");
31 user3.put("userage", 24);
32
33 for(int i=0;i++<5;){
34 arrayList.add(user1);
35 arrayList.add(user2);
36 arrayList.add(user3);
37 }
38
39 SimpleAdapter adapter=new SimpleAdapter(ListViewTestActivity.this, arrayList, R.layout.user, new String[]{"username","userage"},new int[]{R.id.uname,R.id.uage} );
40 //ListActivity提供的绑定数据的方法
41 setListAdapter(adapter);
42 }
43
44 //ListView每一项点击事件,覆盖父类的方法和以前用过的匿名内部类方法不同
45 @Override
46 protected void onListItemClick(ListView l, View v, int position, long id) {
47 String str=((TextView)v.findViewById(R.id.uname)).getText().toString()+"今年"+((TextView)v.findViewById(R.id.uage)).getText().toString();
48 Toast.makeText(ListViewTestActivity.this,str, Toast.LENGTH_LONG).show();
49
50 super.onListItemClick(l, v, position, id);
51 }
52
53 }
效果图:
附上源代码,看会电影睡觉去了 ListViewTest.zip