Freigeben über


Erweitern des RecyclerView-Beispiels

Die in A Basic RecyclerView (Beispiel ) beschriebene einfache App macht eigentlich nicht viel – sie führt einfach einen Bildlauf durch und zeigt eine feste Liste von Fotoelementen an, um das Browsen 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 sein Standard. In den folgenden Abschnitten erfahren Sie, wie Sie Elementklickereignisse behandeln und aktualisieren RecyclerView , wenn sich die zugrunde liegende Datenquelle ändert.

Behandeln von Elementklickereignissen

Wenn ein Benutzer ein Element im RecyclerViewElement berührt, wird ein Elementklickereignis generiert, um die App darüber zu benachrichtigen, welches Element berührt wurde. Dieses Ereignis wird nicht durch – RecyclerView stattdessen erkennt die Elementansicht (die in den Ansichtshalter eingeschlossen ist) Berührungen und meldet diese Berührungen als Klickereignisse.

Um die Behandlung von Elementklickereignissen zu veranschaulichen, erläutern die folgenden Schritte, wie die grundlegende Fotoanzeige-App geändert wird, um zu melden, welches Foto vom Benutzer berührt wurde. Wenn ein Elementklickereignis in der Beispiel-App auftritt, erfolgt die folgende Sequenz:

  1. Das Foto CardView erkennt das Elementklickereignis und benachrichtigt den Adapter.

  2. Der Adapter leitet das Ereignis (mit Elementpositionsinformationen) an den Elementklickhandler der Aktivität weiter.

  3. Der Elementklickhandler der Aktivität antwortet auf das Elementklickereignis.

Zunächst wird der Klassendefinition ein aufgerufenes ItemClick Ereignishandlermemm hinzugefügt PhotoAlbumAdapter :

public event EventHandler<int> ItemClick;

Als Nächstes wird eine Elementklick-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 PhotoAlbumAdapter. Ein guter Ort, um dies zu tun, ist unmittelbar nach PhotoAlbumAdapter der Erstellung:

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

In diesem grundlegenden Beispiel erfolgt die Handlerregistrierung in der Standard-AktivitätsmethodeOnCreate, aber eine Produktions-App registriert den Handler möglicherweise in OnResume und hebt sie auf – weitere Informationen finden Sie im OnPause Aktivitätslebenszyklus.

PhotoAlbumAdapter wird jetzt aufgerufen OnItemClick , wenn es ein Elementklick-Ereignis empfängt. 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 Elementklickereignisse aus Elementansichten. Bevor dieser Listener mit 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 ist der geänderte 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 den CardView Benutzer, der vom Benutzer berührt wurde. Beachten Sie, dass die Basisklasse des Ansichtshalters die Layoutposition des Elements (CardView) kennt, das es 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 in der Anzeige dazu, dass ein Popup angezeigt wird, das meldet, welches Foto berührt wurde:

Beispiel-Popup, das angezeigt wird, wenn auf eine Fotokarte getippt wird

In diesem Beispiel wird nur ein Ansatz für die Implementierung von Ereignishandlern mit RecyclerView. Ein weiterer Ansatz, der hier verwendet werden könnte, ist das Platzieren von Ereignissen auf dem Sichthalter und das Abonnieren des Adapters für diese Ereignisse. Wenn die Beispielfoto-App eine Fotobearbeitungsfunktion bereitgestellt hat, sind für die ImageView und die TextView einzelnen Ereignisse CardViewseparate Ereignisse erforderlich: Touches auf dem TextView Bildschirm würden ein EditView Dialogfeld starten, mit dem der Benutzer die Untertitel bearbeiten kann, und die Fingereingaben würden ImageView ein Foto-Touchup-Tool starten, mit dem der Benutzer das Foto zuschneiden oder drehen kann. Je nach den Anforderungen Ihrer App müssen Sie den besten Ansatz für die Behandlung und Reaktion auf Touchereignisse entwerfen.

Um zu veranschaulichen, wie RecyclerView aktualisiert werden kann, wenn sich das Dataset ändert, kann die Beispielfotoanzeige-App so geändert werden, dass ein Foto in der Datenquelle zufällig ausgewählt und mit dem ersten Foto ausgetauscht wird. Zuerst 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 wird Code am Ende der Methode der Standard Aktivität OnCreate 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 vertauscht ein Foto zufällig mit dem ersten Foto in der Datenquelle und gibt dann den Index des zufällig ausgetauschten 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 Stand 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 wurden zwei Elemente geändert: das erste Foto und das getauschte Foto). Dadurch wird RecyclerView die Anzeige aktualisiert, 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 "Wahlauswahl " getippt wird, wird die Anzeige aktualisiert, RecyclerView um anzuzeigen, dass ein Foto in der Sammlung weiter unten mit dem ersten Foto in der Sammlung ausgetauscht wurde:

Erster Screenshot vor dem Tausch, zweiter Screenshot nach dem Tausch

Es könnte natürlich aufgerufen werden, anstatt die beiden Aufrufe NotifyItemChangedauszuführen, aber dies würde dazu zwingenRecyclerView, NotifyDataSetChanged die gesamte Sammlung zu aktualisieren, obwohl nur zwei Elemente in der Auflistung geändert wurden. Anrufe NotifyItemChanged sind wesentlich effizienter als Anrufe NotifyDataSetChanged.