标签:
ListView是Android开发中比较常用的一个组件,它以列表的形式展示具体内容,并且能够根据数据的长度自适应显示。比如说我们手机里的通讯录就使用到了ListView显示联系人信息。ListView同时也是所有Android UI控件中最为麻烦的控件,之所以麻烦就是因为它的各种的适配器特别麻烦。
创建ListView有两种方式:
1、直接创建ListView
2、让Activity继承ListActivity
列表的显示需要三个元素:
1.ListVeiw :用来展示列表的View。
2.适配器 :用来把数据映射到ListView上的中介。
3.数据集 :具体的将被映射的字符串,图片,或者基本组件。
根据列表的适配器类型,列表分为四种,ArrayAdapter、SimpleAdapter、SimpleCursorAdapter以及自定义Adapter。
其中以ArrayAdapter最为简单,只能展示一行字。SimpleAdapter有最好的扩充性,可以自定义出各种效果。 SimpleCursorAdapter可以认为是SimpleAdapter对数据库的简单结合,可以方面的把数据库的内容以列表的形式展示出来。
下面我们就通过几个简单的例子讲解一下通过各种适配器来构建ListView。
新建一个Android项目:ListViewDemo,同时新建一个类ListViewDemoActivity继承Activity,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
package
com.liuzhichao.listview; import
android.app.Activity; import
android.os.Bundle; import
android.widget.ArrayAdapter; import
android.widget.ListView; public
class ListViewDemoActivity extends Activity { //定义一个ListView
private
ListView mListView; //定义一个String数组,数组里的数据就是ListView里的一项
private
String[] items={ "1、ArrayAdapter_List" , "2、SimpleAdapter_List" , "3、SimpleCursorAdapter_List" , "4、MyAdapter_List" };
@Override
public
void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState);
//new一个ListView
mListView
= new
ListView( this );
//通过setAdapter构建一个ArrayAdapter将items与mListView"绑定"
mListView.setAdapter( new
ArrayAdapter<String>( this ,
android.R.layout.simple_list_item_1,
items)); //显示mListView
setContentView(mListView);
}
} |
上面代码使用了ArrayAdapter(Context context, int textViewResourceId, List<T> objects)来装配数据,要装配这些数据就需要一个连接ListView视图对象和数组数据的适配器来两者的适配工作,ArrayAdapter的构造需要三个参数,依次为this,布局文件(注意这里的布局文件描述的是列表的每一行的布局,android.R.layout.simple_list_item_1是系统定义好的布局文件只显示一行文字,数据源(一个List集合)。同时用setAdapter()完成适配的最后工作。运行后的现实结构如下图:
使用simpleAdapter的数据用一般都是HashMap构成的List,list的每一节对应ListView的每一行。HashMap的每个键值数据映射到布局文件中对应id的组件上。下面我们使用SimpleAdapter模拟一个通讯录。
因为系统没有对应的布局文件可用,我们可以自己定义一个布局info.xml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
<?xml
version= "1.0"
encoding= "utf-8" ?>
<RelativeLayout
xmlns:android= "http://schemas.android.com/apk/res/android" android:layout_width= "fill_parent" android:layout_height= "fill_parent"
> <ImageView
android:id= "@+id/info_img" android:layout_width= "wrap_content" android:layout_height= "wrap_content" android:layout_marginLeft= "3dp" android:src= "@drawable/ic_launcher" />
<TextView
android:id= "@+id/info_name" android:layout_width= "wrap_content" android:layout_height= "wrap_content" android:layout_toRightOf= "@id/info_img" android:layout_marginTop= "5dp" />
<TextView
android:id= "@+id/info_phone" android:layout_width= "wrap_content" android:layout_height= "wrap_content" android:layout_below= "@id/info_name" android:layout_toRightOf= "@id/info_img" android:layout_alignBaseline= "@id/info_img" />
<TextView
android:id= "@+id/info_region" android:layout_width= "wrap_content" android:layout_height= "wrap_content" android:layout_toRightOf= "@id/info_phone" android:layout_alignBaseline= "@id/info_phone" android:layout_marginLeft= "10dip" />
</RelativeLayout> |
新建一个SimpleAdapterListView继续Activity,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
package
com.liuzhichao.listview; import
java.util.ArrayList; import
java.util.HashMap; import
java.util.Map; import
android.app.Activity; import
android.os.Bundle; import
android.widget.ListView; import
android.widget.SimpleAdapter; public
class SimpleAdapterListView extends Activity{ //分别定义通讯录中的用户名、电话、地区等信息
private
String[] info_Names={ "李方刚" , "李玉刚" , "李刚" , "刘产" , "扬伟" , "范剑" };
private
String[] info_Phones={ "13844445144" , "13844444444" , "13444445144" , "13544445144" , "13644445144" , "13744445144" };
private
String[] info_Regions={ "火星" , "水星" , "木星" , "月球" , "美国" , "未知地区" };
//定义一个ArrayList数组,每一条数据对应通讯录中的一个联系人信息
private
ArrayList<Map<String,Object>> mInfos= new
ArrayList<Map<String,Object>>(); //定义一个ListView
private
ListView mListView; @Override
protected
void onCreate(Bundle savedInstanceState) { //
TODO Auto-generated method stub super .onCreate(savedInstanceState);
//new一个ListView
mListView
= new
ListView( this );
//添加联系人信息
for (int
i=0;i<info_Names.length;i++){ Map<String,Object>
item = new
HashMap<String,Object>(); item.put( "img" ,
R.drawable.contact_img); item.put( "name" ,
info_Names[i]); item.put( "phone" ,
info_Phones[i]); item.put( "region" ,
info_Regions[i]); mInfos.add(item);
}
//定义一个SimpleAdapter
SimpleAdapter
adapter = new
SimpleAdapter( this ,
mInfos, R.layout.info, new
String[]{ "img" , "name" , "phone" , "region" },
new
int[]{R.id.info_img,R.id.info_name,R.id.info_phone,R.id.info_region}); //设置mListView的适配器为adapter
mListView.setAdapter(adapter);
setContentView(mListView);
}
} |
使用simpleAdapter的数据用一般都是HashMap构成的List,list的每一节对应ListView的每一行。HashMap的每个键 值数据映射到布局文件中对应id的组件上。因为系统没有对应的布局文件可用,我们可以自己定义一个布局info.xml。运行效果如下图:
我相信肯定有人对new SimpleAdapter()中的参数有一些疑问,下面我们就来看一下SimpleAdapter的构造函数:SimpleAdapter(Contextcontext, List <? extends Map <String, ?>> data, int resource, String[] from, int[] to) ,context相信不用解释了,假设将SimpleAdapter用于ListView。那么ListView的每一个列表项就是resource参数值指定的布局。而data参数就是要加载到ListView中的数据。那么from和to呢?在加载列表项时,需要通过组件的id和data参数中List元素中的Map对象对应。因此,from参数为Map对象的key,而to表示组件的id,例如,本例中的参数值为from=new String[]{“img”,”name”,”phone”,”region”},to=new int[]{R.id.info_img,R.id.info_name,R.id.info_phone,R.id.info_region}),意思就是将Map对象中key为”img”的value绑定到R.id.info_img,将Map对象中key为”name”的value绑定到R.id.info_name,phone、region也类似。所以from和to中的参数是一一对应的关系。同时 from又是对应的Map中的key,to又是对应布局文件中相应组件的ID。
相比SimpleAdapter,SimpleCursorAdapter 就是方便把从游标得到的数据进行列表显示,并可以把指定的列映射到对应的组件中。SimpleCursorAdapter的构造函数与SimpleAdapter的区别就是多了一个Cursor c:SimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to),Cursor就是游标,如果你不清楚游标的概念,就想像成数据查询后的一个结果集。下面是一个通过SimpleCursorAdapter 使用ListView显示系统通讯录中联系人的例子。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
package
com.liuzhichao.listview; import
android.app.Activity; import
android.database.Cursor; import
android.os.Bundle; import
android.provider.ContactsContract.Contacts; import
android.widget.ListView; import
android.widget.SimpleCursorAdapter; public
class SimpleCursorAdapterActivity extends Activity { private
ListView mListView; @Override
protected
void onCreate(Bundle savedInstanceState) { //
TODO Auto-generated method stub super .onCreate(savedInstanceState);
mListView
= new
ListView( this );
Cursor
cursor= this .getContentResolver().query(Contacts.CONTENT_URI,
null ,
null ,
null ,
null );
SimpleCursorAdapter
adapter= new
SimpleCursorAdapter( this ,
android.R.layout.simple_expandable_list_item_2, cursor, new
String[]{Contacts.DISPLAY_NAME}, new
int[]{android.R.id.text1}); mListView.setAdapter(adapter);
setContentView(mListView);
}
} |
注意:在读取系统通讯录时,需要如下权限:
1
|
<uses-permission
android:name= "android.permission.READ_CONTACTS" /> |
左图上是系统通讯录中的联系人,右图是运行的结果。
当我们使用系统自带的ArrayAdapter、SimpleAdapter和SimpleCursorAdapter适配器时,对于事件的响应只能局限在一个行单位。假设一行里面有一个按钮和一个图片控件,它们之间的响应操作是不一样的。若采用系统自带的适配器,就不能精确到每个控件的响应事件。这时,我们一般采取自定义适配器来实现这个比较精确地请求。我们再新建一个MyAdapterListActivity继承Activity,使用自定义适配器来实现SimpleAdapterListView中的效果,并新增一个多选框和按钮。效果如下:
MyAdapterListActivity.java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
|
package
com.liuzhichao.listview; import
java.util.ArrayList; import
java.util.HashMap; import
java.util.List; import
java.util.Map; import
android.app.Activity; import
android.app.AlertDialog; import
android.content.Context; import
android.os.Bundle; import
android.view.LayoutInflater; import
android.view.View; import
android.view.ViewGroup; import
android.widget.BaseAdapter; import
android.widget.Button; import
android.widget.CheckBox; import
android.widget.CompoundButton; import
android.widget.ImageView; import
android.widget.ListView; import
android.widget.TextView; public
class MyAdapterListActivity extends Activity { //分别定义通讯录中的用户名、电话、地区等信息
private
String[] info_Names={ "史珍香" , "赖月京" , "秦寿生" , "刘产" , "扬伟" , "范剑" };
private
String[] info_Phones={ "13844445144" , "13844444444" , "13444445144" , "13544445144" , "13644445144" , "13744445144" };
private
String[] info_Regions={ "火星" , "水星" , "木星" , "月球" , "美国" , "未知" };
//定义一个ArrayList数组,每一条数据对应通讯录中的一个联系人信息
private
ArrayList<Map<String,Object>> mInfos= new
ArrayList<Map<String,Object>>(); //定义一个ListView
private
ListView mListView; @Override
protected
void onCreate(Bundle savedInstanceState) { //
TODO Auto-generated method stub super .onCreate(savedInstanceState);
//new一个ListView
mListView
= new
ListView( this );
//添加联系人信息
for (int
i=0;i<info_Names.length;i++){ Map<String,Object>
item = new
HashMap<String,Object>(); item.put( "img" ,
R.drawable.contact_img); item.put( "name" ,
info_Names[i]); item.put( "phone" ,
info_Phones[i]); item.put( "region" ,
info_Regions[i]); mInfos.add(item);
}
MyAdapter
adapter = new
MyAdapter( this ,
mInfos); mListView.setAdapter(adapter);
setContentView(mListView);
}
private
class MyAdapter extends BaseAdapter { private
Context context; //运行上下文
private
List<Map<String, Object>> listItems; //联系人信息集合
private
LayoutInflater listContainer; //视图容器
private
boolean[] hasChecked; //记录联系人选中状态
public
final class ListItemView{ //自定义控件集合
public
ImageView img; public
TextView name; public
TextView phone; public
TextView region; public
CheckBox check; public
Button detail; }
public
MyAdapter(Context context, List<Map<String, Object>> listItems) { this .context
= context; listContainer
= LayoutInflater.from(context); //创建视图容器并设置上下文
this .listItems
= listItems; hasChecked
= new
boolean[getCount()]; }
public
int getCount() { return
listItems.size(); }
public
Object getItem(int position) { return
null ;
}
public
long getItemId(int position) { return
0; }
public
View getView(int position, View convertView, ViewGroup parent) { final
int selectID = position; ListItemView
listItemView = null ;
if
(convertView == null )
{ listItemView
= new
ListItemView(); //获取list_item布局文件的视图
convertView
= listContainer.inflate(R.layout.myinfo, null );
//获取控件对象
listItemView.img
= (ImageView)convertView.findViewById(R.id.info_img); listItemView.name
= (TextView)convertView.findViewById(R.id.info_name); listItemView.phone
= (TextView)convertView.findViewById(R.id.info_phone); listItemView.region
= (TextView)convertView.findViewById(R.id.info_region); listItemView.detail=
(Button)convertView.findViewById(R.id.btn); listItemView.check
= (CheckBox)convertView.findViewById(R.id.checkBox); //设置控件集到convertView
convertView.setTag(listItemView);
//设置联系人信息
listItemView.img.setBackgroundResource((Integer)
listItems.get( position).get( "img" ));
listItemView.name.setText((String)
listItems.get( position).get( "name" ));
listItemView.phone.setText((String)
listItems.get( position).get( "phone" ));
listItemView.region.setText((String)
listItems.get( position).get( "region" ));
//More按钮事件
listItemView.detail.setOnClickListener( new
View.OnClickListener() { public
void onClick(View v) { showDetailInfo(selectID);
}
});
//
注册多选框状态事件处理 listItemView.check
.setOnCheckedChangeListener( new
CheckBox.OnCheckedChangeListener() { public
void onCheckedChanged(CompoundButton buttonView, boolean
isChecked) { //记录联系人选中状态
checkedChange(selectID);
}
});
} else
{ listItemView
= (ListItemView)convertView.getTag(); }
return
convertView; }
/**
*
记录勾选了哪个联系人 *
@param checkedID 选中的联系人序号 */ private
void checkedChange(int checkedID) { hasChecked[checkedID]
= !hasChecked(checkedID); }
/**
*
判断联系人是否选择 *
@param checkedID 联系人序号 *
@return 返回是否选中状态 */ public
boolean hasChecked(int checkedID) { return
hasChecked[checkedID]; }
/**
*
显示物品详情 *
@param clickID */ private
void showDetailInfo(int clickID) { new
AlertDialog.Builder(context) .setIcon(Integer.parseInt(listItems.get(clickID).get( "img" ).toString()))
.setTitle(listItems.get(clickID).get( "name" )+ "详细信息" )
.setMessage( "电话:" +listItems.get(clickID).get( "phone" ).toString()+ "
地区:" +listItems.get(clickID).get( "region" ).toString())
.setPositiveButton( "确定" ,
null )
.show();
}
}
} |
myinfo.xml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
<?xml
version= "1.0"
encoding= "utf-8" ?>
<RelativeLayout
xmlns:android= "http://schemas.android.com/apk/res/android" android:layout_width= "fill_parent" android:layout_height= "fill_parent"
> <ImageView
android:id= "@+id/info_img" android:layout_width= "wrap_content" android:layout_height= "wrap_content" android:layout_marginLeft= "3dp" />
<TextView
android:id= "@+id/info_name" android:layout_width= "wrap_content" android:layout_height= "wrap_content" android:layout_toRightOf= "@id/info_img" android:layout_marginTop= "5dp" />
<TextView
android:id= "@+id/info_phone" android:layout_width= "wrap_content" android:layout_height= "wrap_content" android:layout_below= "@id/info_name" android:layout_toRightOf= "@id/info_img" android:layout_alignBaseline= "@id/info_img" />
<TextView
android:id= "@+id/info_region" android:layout_width= "wrap_content" android:layout_height= "wrap_content" android:layout_toRightOf= "@id/info_phone" android:layout_alignBaseline= "@id/info_phone" android:layout_marginLeft= "10dip" />
<CheckBox
android:id= "@+id/checkBox" android:layout_width= "wrap_content" android:layout_height= "wrap_content" android:layout_marginLeft= "5dp" android:layout_alignBaseline= "@id/info_img" android:layout_toRightOf= "@id/info_region" />
<Button
android:id= "@+id/btn" android:layout_width= "wrap_content" android:layout_height= "wrap_content" android:layout_alignBaseline= "@id/checkBox" android:layout_toRightOf= "@id/checkBox" android:text= "More..." />
</RelativeLayout> |
2、让Activity继承ListActivity构建ListView
如果程序的窗口仅仅需要显示一个列表,则可以让Activity直接继续ListActivity来实现。ListActivity的子类无需调用setContentView()方法来显示某个界面,而是可以直接传入一个Adapter,ListActivity的子类就可以呈现出一个列表。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
package
com.liuzhichao.listview; import
java.util.ArrayList; import
java.util.HashMap; import
java.util.Map; import
android.app.ListActivity; import
android.os.Bundle; import
android.widget.SimpleAdapter; public
class ListActivityList extends ListActivity { //分别定义通讯录中的用户名、电话、地区等信息
private
String[] info_Names={ "***" , "***" , "***" , "***" , "***" , "***" };
private
String[] info_Phones={ "13844445144" , "13844444444" , "13444445144" , "13544445144" , "13644445144" , "13744445144" };
private
String[] info_Regions={ "火星" , "水星" , "木星" , "月球" , "美国" , "未知地区" };
//定义一个ArrayList数组,每一条数据对应通讯录中的一个联系人信息
private
ArrayList<Map<String,Object>> mInfos= new
ArrayList<Map<String,Object>>(); @Override
protected
void onCreate(Bundle savedInstanceState) { //
TODO Auto-generated method stub super .onCreate(savedInstanceState);
//添加联系人信息
for (int
i=0;i<info_Names.length;i++){ Map<String,Object>
item = new
HashMap<String,Object>(); item.put( "img" ,
R.drawable.contact_img); item.put( "name" ,
info_Names[i]); item.put( "phone" ,
info_Phones[i]); item.put( "region" ,
info_Regions[i]); mInfos.add(item);
}
//定义一个SimpleAdapter
SimpleAdapter
adapter = new
SimpleAdapter( this ,
mInfos, R.layout.info, new
String[]{ "img" , "name" , "phone" , "region" },
new
int[]{R.id.info_img,R.id.info_name,R.id.info_phone,R.id.info_region}); //本例中没有声明一个ListView,但通过继承ListActivity使用setListAdapter然后传入一个适配器即可直接显示一个列表。
setListAdapter(adapter);
}
} |
标签:
原文地址:http://blog.csdn.net/jian_csdn/article/details/43306965