AdapterView 组件时一组重要的组件,AdapterView 本身是一个抽象基类,它派生的子类在用法上十分相似,只是显示界面有一定的区别,因此我们把它们归为一类,针对它们的共性集中讲解,并突出介绍它们的区别。
AdapterView 具有如下特征。
AdapterView 继承了 ViewGroup,它的本质是容器。
AdapterView 可以包括多个 “列表项”,并将多个 “列表项” 以合适的形式显示出来。
AdapterView 显示的多个 “列表项” 由 Adapter 提供。调用 AdapterView 的 setAdapter(Adapter) 方法设置 Adapter 即可。
AdapterView 及其子类的继承关系类图如图 2.34 所示。
从图 2.34 不难看出,AdapterView 派生了三个子类:AbsListView、AbsSpinner 和 AdapterViewAnimator,这三个子类依然是抽象的,实际使用时往往采用它们的子类。
1,列表视图(ListView)和 ListActivity
ListView 是手机系统中使用非常广泛的一种组件,它们垂直列表的形式显示所有列表项。
创建 ListView 有如下两种方式。
直接使用 ListView 进行创建。
让 Activity 继承 ListActivity(相当于该 Activity 显示的组件为 ListView)。
一旦在程序中获得了 ListView 之后,接下来就需要为 ListView 设置它要显示的列表项了。在这一点上,ListView 表显示出 AdapterView 的特征:通过 setAdapter(Adapter) 方法为止提供 Adapter、并由 Adapter 提供列表项即可。
ListView、GridView、Spinner、Gallery 等 AdapterView 都只是容器。而 Adapter 负责提供每个 “列表项” 组件,AdapterView 则负责采用合适的方式显示这些列表项。
ABSListView 提供了如表 2.18 所示的 XML 属性。
ListView 提供了如表 2.19 所示的常用 XML 属性。
下面通过几个实例来示范 ListView 的功能和用法。
实例:改变分隔条、基于数组的 ListView
下面的界面布局中定义了两个 ListView。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<!-- 直接使用数组资源给出列表项 -->
<!-- 设置使用红色的分隔条 -->
<ListView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:entries="@array/books"
android:divider="#f00"
android:dividerHeight="2px"
android:headerDividersEnabled="false"
/>
</LinearLayout>
上面的界面布局中定义了一个 ListView,并通过 android:entries 指定了列表项数组,该 ListView 还通过 android:divider 改变了列表项之间的分隔条。
上面第一个 ListView 指定了 android:entries="@array/books",该属性值用到了数组资源,因此还需要在应用中定义一个名为 books 的数组,定义数组的资源文件如下。
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<string-array name="books">
<item>疯狂Java讲义</item>
<item>疯狂Ajax讲义</item>
<item>疯狂XML讲义</item>
<item>疯狂Android讲义</item>
</string-array>
</resources>
使用数组创建 ListView 十分简单,但这种 ListView 能定制的内容很少,甚至连每个列表项的字号大小、颜色都不能改变。
如果想对 ListView 的外观、行为进行定制,就需要把 ListView 作为 AdapterView 使用,通过 Adapter 控制每个列表项的外观和行为。
2,Adapter 接口及实现类
Adapter 本身只是一个接口,它派生了 ListAdapter 和 SpinnerAdapter 两个子接口,其中 ListAdapter 为 AbsListView 提供列表项,而 SpinnerAdapter 为 AbsSpinner 提供列表项。Adapter 接口及其实现类的继承关系类图如图 2.36 所示。
图 2.36 所示继承类图中粗线框标出的 Adapter 是比较常用的 Adapter。从图 2.36 中所示的继承关系可以看出,几乎所有 Adapter 都继承了 BaseAdapter,而 BaseAdapter 同时实现了 ListAdapter、SpinnerAdapter 两个接口,因此 BaseAdapter 及其子类可以同时为 AbsListView、AbsSpinner 提供列表项。
Adapter 常用的实现类如下。
ArrayAdapter:简单、易用的 Adapter,通常用于将数组或 List 集合的多个值包装成多个列表项。
SimpleAdapter:并不简单、功能强大的 Adapter,可用于将 List 集合的多个对象包装成多个列表项。
SimpleCursorAdapter:与 SimpleAdapter 基本相似,只是用于包装 Cursor 提供的数据。
BaseAdapter:通常用于被扩展。扩张 BaseAdapter 可以对各列表项进行最大限度的定制。
下面先通过 ArrayAdapter 来实现 ListView。
实例:使用 ArrayAdapter 创建 ListView
下面的实例在界面布局中定义了两个 ListView。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<!-- 设置使用红色的分隔条 -->
<ListView
android:id="@+id/list1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:divider="#f00"
android:dividerHeight="2px"
android:headerDividersEnabled="false"
/>
<!-- 设置使用绿色的分隔条 -->
<ListView
android:id="@+id/list2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:divider="#0f0"
android:dividerHeight="2px"
android:headerDividersEnabled="false"
/>
</LinearLayout>
上面的布局文件定义了两个 ListView,但这两个 ListView 都没有指定 android:entries 属性,这意味着它们都需要通过 Adapter 来提供列表项。
接下来 Activity 为两个 ListView 提供 Adapter,Adapter 决定 ListView 所显示的列表项。程序如下。
public class ArrayAdapterTest extends Activity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ListView list1 = (ListView) findViewById(R.id.list1);
// 定义一个数组
String[] arr1 = { "孙悟空", "猪八戒", "牛魔王" };
// 将数组包装ArrayAdapter
ArrayAdapter<String> adapter1 = new ArrayAdapter<String>
(this, R.layout.array_item, arr1);
// 为ListView设置Adapter
list1.setAdapter(adapter1);
ListView list2 = (ListView) findViewById(R.id.list2);
// 定义一个数组
String[] arr2 = { "Java", "Hibernate", "Spring" , "Android" };
// 将数组包装ArrayAdapter
ArrayAdapter<String> adapter2 = new ArrayAdapter<String>
(this, R.layout.checked_item, arr2);
// 为ListView设置Adapter
list2.setAdapter(adapter2);
}
}
上面的程序中创建了两个 ArrayAdapter,创建 ArrayAdapter 时必须指定如下三个参数。
Context:这个参数无须多说,它代表了访问整个 Android 应用的接口。几乎创建所有组件都需要传入 Context 对象。
textViewResourceId:一个资源 ID,该资源 ID 代表一个 TextView,该 TextView 组件将作为 ArrayAdapter 的列表项组件。
数组或 List:该数组或 List 将负责为多个列表项提供数据。
从上面的介绍不难看出,创建 ArrayAdapter 时传入的第二个参数控制每个列表项的组件,第三个参数则负责为列表项提供数据。该数组或 List 包含多少个元素,将生成多少个列表项,每个列表项都是 TextView 组件,TextView 组件显示的文本由数组或 List 的元素提供。
以上的代码中第一个 ArrayAdapter 为例,该 ArrayAdapter 对应的数组为 { "孙悟空","猪八戒","牛魔王" } ,该数组将会负责生成一个包含三个列表项的 ArrayAdapter,,每个列表项的组件外观由 R.layout.arra_item 布局文件(该布局文件只是一个 TextView 组件)控制,第一个 TextView 列表项显示的文本为 “孙悟空”,第二个 TextView 列表项显示的文本为 “猪八戒” ......
上面的程序中 R.layout.array_item 布局文件如下。
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/TextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="24dp"
android:padding="10px"
android:shadowColor="#f0f"
android:shadowDx="4"
android:shadowDy="4"
android:shadowRadius="2"/>
上面的程序中 R.layout.checked_item 布局文件与上面的布局文件类似。
运行上面的程序将可以看到如图 2.37 所示效果。
实例:基于 ListActivity 实现列表
如果程序的窗口仅仅需要显示一个列表,则可以直接让 Activity 继承 ListActivity 来实现,ListActivity 的子类无须调用 setContentView() 方法来显示某个界面,而是可以直接传入一个内容 Adapter,ListActivity 的子类就呈现出一个列表。
例如如下程序。
public class ListActivityTest extends ListActivity
{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// 无需使用布局文件
String[] arr = { "孙悟空", "猪八戒", "唐僧" };
// 创建ArrayAdapter对象
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_multiple_choice, arr);
// 设置该窗口显示列表
setListAdapter(adapter);
}
}
上面程序的 Activity 继承了 ListActivity,ListActivity 无须界面布局文件 —— 相当于它的布局文件中只有一个 ListView,因此只要为 ListActivity 设置 Adapter 即可。上面的程序使用 Android 提供的 R.layout.simple_list_item_multiple_choice 布局文件作为列表项组件。
运行上面的程序将看到如图 2.38 所示界面。
ListActivity 的默认布局时由一个位于屏幕中心的列表组成的。实际上,开发者完全可以在 onCreate() 方法中通过 setContentView(int layoutId) 方法设置用户的自定义布局。
需要指出的是,在开发者指定的界面布局中应该包含一个 id 为 "@+id/android:list" (如果是使用代码的形式,则是 android.R.id.list)的 ListView。例如包含如下代码片段:
<ListView android:id="@+id/android:list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:drawSelectorOnTop="false"/>
实例:使用 SimpleAdapter 创建 ListView
通过 ArrayAdapter 实现 Adapter 虽然简单、易用,但 ArrayAdapter 的功能比较有限。它的每个列表项只能是 TextView。如果开发者需要实现更复杂的列表项,则可以考虑使用 SimpleAdapter。
不要被 SimpleAdapter 的名字欺骗,SimpleAdapter 并不简单,而且它的功能非常强大。ListView 的大部分应用场景,都可以通过 SimpleAdapter 来提供列表项。
例如下面先定义如下界面布局文件。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="