步骤 2:创建资源文件
创建一个新的布局 XML 文件,其根元素为 ,并将其命名为项.xml。将“大文本”微件拖放到其中,并将其属性的值设置为cheese_name。布局 XML 文件应如下所示:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/activity_horizontal_margin">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Large Text"
android:id="@+id/cheese_name" />
</LinearLayout>
步骤 3:创建适配器
在活动中,使用类的构造函数创建类的新实例。作为其参数,传递资源文件的名称、的标识符和对数组的引用。适配器现在已准备就绪。
ArrayAdapter<String> cheeseAdapter =
new ArrayAdapter<String>(this,
R.layout.item,
R.id.cheese_name,
cheeses
);
4. 创建列表
要显示可垂直滚动的项目列表,可以使用微件。要将小部件添加到活动中,可以将其拖放到活动的布局 XML 文件中,也可以使用 Java 代码中的构造函数创建小组件。
ListView cheeseList = new ListView(this);
setContentView(cheeseList);
若要将其绑定到我们在上一步中创建的适配器,请调用如下所示的方法。
cheeseList.setAdapter(cheeseAdapter);
如果现在运行应用,则应该能够以列表的形式查看数组的内容。
5. 创建网格
要显示可垂直滚动的项目二维网格,可以使用微件。两者都是抽象类的子类,它们有许多相似之处。因此,如果您知道如何使用其中一个,那么您也知道如何使用另一个。
使用类的构造函数创建一个新实例,并将其传递给活动的方法。
GridView cheeseGrid = new GridView(this);
setContentView(cheeseGrid);
若要设置网格中的列数,请调用其方法。我将把它做成一个两列的网格。
cheeseGrid.setNumColumns(2);
通常,您希望使用 、 和 方法来调整列的宽度和之间的间距。请注意,这些方法使用像素作为其单位。setColumnWidth()setVerticalSpacing()setHorizontalSpacing()
cheeseGrid.setColumnWidth(60);
cheeseGrid.setVerticalSpacing(20);
cheeseGrid.setHorizontalSpacing(20);
现在,您可以使用该方法将 绑定到我们之前创建的适配器。
cheeseGrid.setAdapter(cheeseAdapter);`
再次运行应用以查看外观。
6. 添加事件侦听器
可以侦听适配器视图中项目的单击和长单击事件。例如,让我们将单击事件侦听器添加到 GridView
创建实现接口的匿名类的新实例,并将其传递给对象的方法。安卓工作室会为接口的方法自动生成一个存根。您会注意到,该方法的参数包含一个整数,用于指定列表项的位置。您可以使用此整数来找出用户单击的数据集中的哪个项目。AdapterView.OnItemClickListenersetOnItemClickListener()GridViewonItemClick()
下面的代码演示如何在每次单击 中的项时将简单消息显示为小吃栏。
cheeseGrid.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView,
View view, int position, long rowId) {
// Generate a message based on the position
String message = "You clicked on " + cheeses[position];
// Use the message to create a Snackbar
Snackbar.make(adapterView, message, Snackbar.LENGTH_LONG)
.show(); // Show the Snackbar
}
});
如果运行应用并单击网格中的任意项目,屏幕底部将显示一条消息。请注意,您可以使用相同的代码来侦听。
7. 扩展ArrayAdapter
在它生成的对象的布局中只能处理一个小部件。要拓宽它的功能,你必须扩展它。但是,在我们这样做之前,让我们创建一个稍微复杂的数据集。
假设我们的数据集包含以下类的对象,而不是字符串:
static class Cheese {
String name;
String description;
public Cheese(String name, String description) {
this.name = name;
this.description = description;
}
}
这是我们将使用的数据集:
Cheese[] cheeses = {
new Cheese("Parmesan", "Hard, granular cheese"),
new Cheese("Ricotta", "Italian whey cheese"),
new Cheese("Fontina", "Italian cow's milk cheese"),
new Cheese("Mozzarella", "Southern Italian buffalo milk cheese"),
new Cheese("Cheddar", "Firm, cow's milk cheese"),
};
如您所见,该类包含两个字段和 。要在列表或网格中显示这两个字段,项目的布局必须包含两个微件。
创建一个新的布局 XML 文件并将其命名为custom_item.xml。向其添加“大文本”和“小文本”构件。将第一个小部件的属性设置为cheese_name将第二个小部件的属性设置为cheese_description。布局 XML 文件的内容现在应如下所示:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/activity_horizontal_margin">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Large Text"
android:id="@+id/cheese_name" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="Small Text"
android:id="@+id/cheese_description" />
</LinearLayout>
还必须能够处理两个小部件。重新访问您的活动,创建一个扩展该类的新匿名类,并重写其方法。确保将数组作为参数传递给其构造函数。
ArrayAdapter<Cheese> cheeseAdapter =
new ArrayAdapter<Cheese>(this, 0, cheeses) {
@Override
public View getView(int position,
View convertView,
ViewGroup parent) {
}
};
在方法内部,必须将参数用作数组的索引,并在该索引处获取项。getView()position
Cheese currentCheese = cheeses[position];
该方法的第二个参数使我们能够重用对象。如果忽略它,适配器视图的性能将很差。首次调用该方法时, 是 。必须通过扩充指定列表项布局的资源文件来初始化它。为此,请使用该方法获取对 的引用并调用其方法。
// Inflate only once
if(convertView == null) {
convertView = getLayoutInflater()
.inflate(R.layout.custom_item, null, false);
}
此时,您可以使用 来获取对布局内小部件的引用,并调用它们的方法以使用数组中的数据对其进行初始化。
TextView cheeseName =
(TextView)convertView.findViewById(R.id.cheese_name);
TextView cheeseDescription =
(TextView)convertView.findViewById(R.id.cheese_description);
cheeseName.setText(currentCheese.name);
cheeseDescription.setText(currentCheese.description);
最后,返回,以便它可用于填充与适配器关联的任何适配器视图。
return convertView;
8. 使用视图支架
适配器视图重复调用该方法以填充自身。因此,您必须尝试尽量减少在其中执行的操作数。getView()
在上一步中,您可能已经注意到,即使我们确保列表项的布局只膨胀一次,每次调用该方法时都会调用该方法,该方法会消耗许多 CPU 周期。
为了避免这种情况并提高适配器视图的性能,我们需要将方法的结果存储在对象中。为此,我们可以使用视图持有者对象,它只不过是一个类的对象,可以存储布局中存在的小部件。
由于布局具有两个构件,因此视图持有者类还必须具有两个构件。我已将类命名为“视图持有者”。
static class ViewHolder{
TextView cheeseName;
TextView cheeseDescription;
}
在该方法中,在放大布局后,现在可以使用该方法初始化视图持有者对象。
ViewHolder viewHolder = new ViewHolder();
viewHolder.cheeseName =
(TextView)convertView.findViewById(R.id.cheese_name);
viewHolder.cheeseDescription =
(TextView)convertView.findViewById(R.id.cheese_description);
要将视图持有者对象存储在 中,请使用其方法。convertViewsetTag()
// Store results of findViewById