Erweitern des RecyclerView-Beispiels

Die in A Basic RecyclerView Example beschriebene einfache App macht eigentlich nicht viel – sie scrollt einfach und zeigt eine feste Liste von Fotoelementen an, um das Durchsuchen zu erleichtern. In realen Anwendungen erwarten Benutzer, dass sie mit der App interagieren können, indem sie auf Elemente in der Anzeige tippen. Außerdem kann sich die zugrunde liegende Datenquelle ändern (oder von der App geändert werden), und der Inhalt der Anzeige muss mit diesen Änderungen konsistent bleiben. In den folgenden Abschnitten erfahren Sie, wie Sie Item-Click-Ereignisse behandeln und aktualisieren RecyclerView , wenn sich die zugrunde liegende Datenquelle ändert.

Behandeln von Item-Click Ereignissen

Wenn ein Benutzer ein Element im RecyclerViewberührt, wird ein Elementklickereignis generiert, um die App darüber zu informieren, welches Element berührt wurde. Dieses Ereignis wird nicht von RecyclerView generiert. Stattdessen erkennt die Elementansicht (die im Ansichtshalter umschlossen ist) Berührungen und meldet diese Berührungen als Klickereignisse.

Zur Veranschaulichung der Behandlung von Elementklickereignissen wird in den folgenden Schritten erläutert, wie die einfache Fotoanzeige-App geändert wird, um zu melden, welches Foto vom Benutzer berührt wurde. Wenn in der Beispiel-App ein Elementklickereignis auftritt, erfolgt die folgende Sequenz:

  1. Das Foto CardView erkennt das Item-Click-Ereignis und benachrichtigt den Adapter.

  2. Der Adapter leitet das Ereignis (mit Elementpositionsinformationen) an den Item-Click-Handler der Aktivität weiter.

  3. Der Item-Click-Handler der Aktivität antwortet auf das Item-Click-Ereignis.

Zunächst wird der PhotoAlbumAdapter Klassendefinition ein Ereignishandlermember namens ItemClick hinzugefügt:

public event EventHandler<int> ItemClick;

Als Nächstes wird eine Item-Click-Ereignishandlermethode hinzugefügt.MainActivity Dieser Handler zeigt kurz ein Popup an, das angibt, welches Fotoelement berührt wurde:

void OnItemClick (object sender, int position)
{
    int photoNum = position + 1;
    Toast.MakeText(this, "This is photo number " + photoNum, ToastLength.Short).Show();
}

Als Nächstes ist eine Codezeile erforderlich, um den OnItemClick Handler bei PhotoAlbumAdapterzu registrieren. Ein guter Ort, um dies zu tun, ist sofort nach der PhotoAlbumAdapter Erstellung:

mAdapter = new PhotoAlbumAdapter (mPhotoAlbum);
mAdapter.ItemClick += OnItemClick;

In diesem einfachen Beispiel erfolgt die Handlerregistrierung in der Methode der Standard AktivitätOnCreate, aber eine Produktions-App kann den Handler in OnResume registrieren und die Registrierung in aufheben. Weitere Informationen finden Sie unter OnPauseAktivitätslebenszyklus.

PhotoAlbumAdapter ruft nun auf OnItemClick , wenn ein Elementklickereignis empfangen wird. Der nächste Schritt besteht darin, einen Handler im Adapter zu erstellen, der dieses ItemClick Ereignis auslöst. Die folgende Methode wird OnClickunmittelbar nach der -Methode des Adapters ItemCount hinzugefügt:

void OnClick (int position)
{
    if (ItemClick != null)
        ItemClick (this, position);
}

Diese OnClick Methode ist der Listener des Adapters für Item-Click-Ereignisse aus Elementansichten. Bevor dieser Listener bei einer Elementansicht (über den Ansichtshalter der Elementansicht) registriert werden kann, muss der PhotoViewHolder Konstruktor geändert werden, um diese Methode als zusätzliches Argument zu akzeptieren und sich beim Elementansichtsereignis Click zu registrierenOnClick. Hier sehen Sie den geänderten PhotoViewHolder Konstruktor:

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);
}

Der itemView Parameter enthält einen Verweis auf die , die CardView vom Benutzer berührt wurde. Beachten Sie, dass die Basisklasse des Ansichtshalters die Layoutposition des Elements (CardView) kennt, das sie darstellt (über die LayoutPosition -Eigenschaft), und diese Position wird an die -Methode des Adapters OnClick übergeben, wenn ein Elementklickereignis stattfindet. Die -Methode des Adapters OnCreateViewHolder wird geändert, um die -Methode des Adapters OnClick an den Konstruktor des Ansichtshalters zu übergeben:

PhotoViewHolder vh = new PhotoViewHolder (itemView, OnClick);

Wenn Sie nun die Beispiel-Fotoanzeige-App erstellen und ausführen, führt das Tippen auf ein Foto im Display dazu, dass ein Popup angezeigt wird, das meldet, welches Foto berührt wurde:

Beispiel-Popup, das angezeigt wird, wenn eine Fotokarte angetippt wird

In diesem Beispiel wird nur ein Ansatz zum Implementieren von Ereignishandlern mit RecyclerViewveranschaulicht. Ein weiterer Ansatz, der hier verwendet werden könnte, ist das Platzieren von Ereignissen auf dem Ansichtshalter und das Abonnieren dieser Ereignisse durch den Adapter. Wenn die Beispielfoto-App eine Fotobearbeitungsfunktion bereitstellt, wären separate Ereignisse für und ImageView in TextView jedem CardViewerforderlich: Touchvorgänge auf der TextView würden ein EditView Dialogfeld starten, in dem der Benutzer die Untertitel bearbeiten kann, und touchiert auf, ImageView um ein Foto-Touchup-Tool zu starten, mit dem der Benutzer das Foto zuschneiden oder drehen kann. Abhängig von den Anforderungen Ihrer App müssen Sie den besten Ansatz für die Behandlung und Reaktion auf Touchereignisse entwerfen.

Um zu veranschaulichen, wie aktualisiert werden kann, wenn sich das Dataset ändert, kann die Beispiel-Fotoanzeige-App so geändert werden, dass RecyclerView ein Foto in der Datenquelle zufällig ausgewählt und mit dem ersten Foto ausgetauscht wird. Zunächst wird dem Main.axml-Layout der Beispielfoto-App eine Schaltfläche "Zufällige Auswahl" hinzugefügt:

<?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>

Als Nächstes OnCreate wird am Ende der Methode der Standard Aktivität Code hinzugefügt, um die Random Pick Schaltfläche im Layout zu suchen und einen Handler an sie anzufügen:

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();
    }
};

Dieser Handler ruft die -Methode des Fotoalbums RandomSwap auf, wenn auf die Schaltfläche "Zufällige Auswahl " getippt wird. Die RandomSwap -Methode tauscht zufällig ein Foto mit dem ersten Foto in der Datenquelle und gibt dann den Index des zufällig getauschten Fotos zurück. Wenn Sie die Beispiel-App mit diesem Code kompilieren und ausführen, führt das Tippen auf die Schaltfläche "Zufällige Auswahl " nicht zu einer Anzeigeänderung, da die RecyclerView Änderung an der Datenquelle nicht bekannt ist.

Um nach Änderungen der Datenquelle auf dem Neuesten zu bleiben RecyclerView , muss der Klickhandler für die Zufällige Auswahl geändert werden, um die Methode des Adapters NotifyItemChanged für jedes Element in der Auflistung aufzurufen, das geändert wurde (in diesem Fall haben sich zwei Elemente geändert: das erste Foto und das getauschte Foto). Dies führt dazu RecyclerView , dass die Anzeige aktualisiert wird, sodass sie mit dem neuen Zustand der Datenquelle konsistent ist:

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);
    }
};

Wenn nun auf die Schaltfläche Zufällige Auswahl getippt wird, wird die Anzeige aktualisiert, RecyclerView um anzuzeigen, dass ein Foto weiter unten in der Sammlung mit dem ersten Foto in der Sammlung getauscht wurde:

Erster Screenshot vor dem Austausch, zweiter Screenshot nach dem Austausch

Natürlich hätte aufgerufen werden können, anstatt die beiden Aufrufe von zu NotifyItemChangedtätigen, aber dies würde erzwingenRecyclerView, NotifyDataSetChanged die gesamte Auflistung zu aktualisieren, obwohl nur zwei Elemente in der Auflistung geändert wurden. Das Aufrufen NotifyItemChanged von ist deutlich effizienter als das Aufrufen von NotifyDataSetChanged.