扩展 RecyclerView 示例
基本 回收器视图示例中 介绍的基本应用实际上没有太大作用 - 它只是滚动并显示固定的照片项列表,以便于浏览。 在实际应用程序中,用户希望能够通过点击屏幕中的项目来与应用交互。 此外,基础数据源可以更改 (或由应用) 更改,并且显示内容必须与这些更改保持一致。 在以下部分中,你将了解如何处理项目单击事件,并在基础数据源更改时进行更新 RecyclerView
。
处理Item-Click事件
当用户触摸 中的 RecyclerView
项时,将生成一个项单击事件,以通知应用所触摸的项。 此事件不是由 RecyclerView
生成,而是将项目视图 (包装在视图持有者中,) 检测触摸并将这些触摸报告为单击事件。
为了说明如何处理项目单击事件,以下步骤说明如何修改基本照片查看应用以报告用户已触摸的照片。 当示例应用中发生项目单击事件时,将发生以下顺序:
照片的
CardView
检测到项目单击事件并通知适配器。适配器将包含项位置信息的事件 () 转发到活动的项单击处理程序。
活动的项单击处理程序响应项单击事件。
首先,将名为 的ItemClick
事件处理程序成员添加到类定义:PhotoAlbumAdapter
public event EventHandler<int> ItemClick;
接下来,将项单击事件处理程序方法添加到 MainActivity
。
此处理程序短暂显示一个 Toast,指示已触摸的照片项:
void OnItemClick (object sender, int position)
{
int photoNum = position + 1;
Toast.MakeText(this, "This is photo number " + photoNum, ToastLength.Short).Show();
}
接下来,需要一行代码来向 OnItemClick
注册处理程序 PhotoAlbumAdapter
。 创建 后 PhotoAlbumAdapter
,可以立即执行此操作:
mAdapter = new PhotoAlbumAdapter (mPhotoAlbum);
mAdapter.ItemClick += OnItemClick;
在此基本示例中,处理程序注册在 main 活动的 OnCreate
方法中发生,但生产应用可能会在 中OnResume
注册处理程序并注销它 OnPause
- 有关详细信息,请参阅活动生命周期。
PhotoAlbumAdapter
现在,当它收到项目单击事件时,将调用 OnItemClick
。 下一步是在适配器中创建引发此 ItemClick
事件的处理程序。 紧接在适配器的 ItemCount
方法OnClick
之后添加以下方法 :
void OnClick (int position)
{
if (ItemClick != null)
ItemClick (this, position);
}
此方法 OnClick
是适配器的 侦听器 ,用于从项视图中单击项的事件。 在通过项视图的视图持有者) 向项视图 (注册此侦听器之前, PhotoViewHolder
必须修改构造函数以接受此方法作为附加参数,并注册 OnClick
到项视图 Click
事件。
下面是修改后的 PhotoViewHolder
构造函数:
public PhotoViewHolder (View itemView, Action<int> listener)
: base (itemView)
{
Image = itemView.FindViewById<ImageView> (Resource.Id.imageView);
Caption = itemView.FindViewById<TextView> (Resource.Id.textView);
itemView.Click += (sender, e) => listener (base.LayoutPosition);
}
参数 itemView
包含对 CardView
用户触摸的 的引用。 请注意,视图持有者基类知道项的布局位置 (CardView
) 它通过 LayoutPosition
属性) 表示 (,并且当发生项目单击事件时,此位置将传递给适配器 OnClick
的 方法。 修改适配器的 OnCreateViewHolder
方法,以将适配器的 OnClick
方法传递给视图持有者的构造函数:
PhotoViewHolder vh = new PhotoViewHolder (itemView, OnClick);
现在,当你生成并运行示例照片查看应用时,点击屏幕中的照片将导致显示一个 Toast,其中报告了已触摸的照片:
此示例仅演示使用 实现事件处理程序的 RecyclerView
一种方法。 可在此处使用的另一种方法是将事件放置在视图持有者上,并让适配器订阅这些事件。 如果示例照片应用提供了照片编辑功能,则 每个 CardView
中的 将需要TextView
ImageView
单独的事件:触摸 TextView
将启动一个EditView
对话框,允许用户编辑描述文字,触摸 ImageView
将启动一个允许用户裁剪或旋转照片的照片触摸工具。 根据应用的需求,必须设计处理和响应触摸事件的最佳方法。
为了演示如何 RecyclerView
在数据集更改时进行更新,可以修改示例照片查看应用,以随机选取数据源中的照片,并将其与第一张照片交换。 首先,将 “随机选取 ”按钮添加到示例照片应用的 Main.axml 布局中:
<?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">
<Button
android:id="@+id/randPickButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Random Pick" />
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:scrollbars="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>
接下来,在 main 活动的 OnCreate
方法末尾添加代码,以在布局中查找Random Pick
按钮并向其附加处理程序:
Button randomPickBtn = FindViewById<Button>(Resource.Id.randPickButton);
randomPickBtn.Click += delegate
{
if (mPhotoAlbum != null)
{
// Randomly swap a photo with the first photo:
int idx = mPhotoAlbum.RandomSwap();
}
};
点击“随机选取”按钮时,此处理程序将调用相册的 RandomSwap
方法。 方法 RandomSwap
随机交换一张照片与数据源中的第一张照片,然后返回随机交换的照片的索引。 使用此代码编译和运行示例应用时,点击 “随机选取 ”按钮不会导致显示更改, RecyclerView
因为 不知道数据源的更改。
若要在数据源更改后保持 RecyclerView
更新,必须修改 随机选取 单击处理程序,以便为集合中已更改的每个项调用适配器 NotifyItemChanged
的 方法 (在本例中,有两个项目已更改:第一张照片和交换的照片) 。 这会导致 RecyclerView
更新其显示,使其与数据源的新状态保持一致:
Button randomPickBtn = FindViewById<Button>(Resource.Id.randPickButton);
randomPickBtn.Click += delegate
{
if (mPhotoAlbum != null)
{
int idx = mPhotoAlbum.RandomSwap();
// First photo has changed:
mAdapter.NotifyItemChanged(0);
// Swapped photo has changed:
mAdapter.NotifyItemChanged(idx);
}
};
现在,点击“ 随机选取 ”按钮时, RecyclerView
会更新显示集合中更下方的照片已与集合中的第一张照片交换:
当然, NotifyDataSetChanged
可以调用 而不是对 NotifyItemChanged
进行两次调用,但这样做将强制 RecyclerView
刷新整个集合,即使集合中只有两个项已更改。 调用 比调用 NotifyItemChanged
NotifyDataSetChanged
效率高得多。