Freigeben über


Ein einfaches RecyclerView-Beispiel

Um die Funktionsweise in einer typischen Anwendung zu verstehen RecyclerView , untersucht dieses Thema ein einfaches Codebeispiel, das zum Anzeigen einer großen Sammlung von Fotos verwendet RecyclerView wird:

Zwei Screenshots einer RecyclerView-App, die CardViews zum Anzeigen von Fotos verwendet

RecyclerViewer verwendet CardView , um jedes Fotoelement im RecyclerView Layout zu implementieren. Aufgrund der RecyclerViewLeistungsvorteile ist diese Beispiel-App in der Lage, einen schnellen Bildlauf durch eine große Sammlung von Fotos reibungslos und ohne spürbare Verzögerungen zu ermöglichen.

Beispieldatenquelle

In dieser Beispiel-App liefert RecyclerView eine "Fotoalbum"-Datenquelle (dargestellt durch die PhotoAlbum Klasse) Elementinhalte. PhotoAlbum ist eine Sammlung von Fotos mit Beschriftungen; Wenn Sie es instanziieren, erhalten Sie eine vorgefertigte Sammlung von 32 Fotos:

PhotoAlbum mPhotoAlbum = new PhotoAlbum ();

Jede Fotoinstanz in PhotoAlbum macht Eigenschaften verfügbar, mit denen Sie die Bildressourcen-ID PhotoIDund die Beschriftungszeichenfolge Captionlesen können. Die Sammlung von Fotos ist so organisiert, dass auf jedes Foto von einem Indexer zugegriffen werden kann. Die folgenden Codezeilen greifen beispielsweise auf die Bildressourcen-ID und die Beschriftung für das zehnte Foto in der Auflistung zu:

int imageId = mPhotoAlbum[9].ImageId;
string caption = mPhotoAlbum[9].Caption;

PhotoAlbum Stellt außerdem eine RandomSwap Methode bereit, mit der Sie das erste Foto in der Sammlung mit einem zufällig ausgewählten Foto an anderer Stelle in der Sammlung austauschen können:

mPhotoAlbum.RandomSwap ();

Da die Implementierungsdetails PhotoAlbum für das Verständnis RecyclerViewnicht relevant sind, wird der PhotoAlbum Quellcode hier nicht dargestellt.

Layout und Initialisierung

Die Layoutdatei " Main.axml" besteht aus einem einzelnen RecyclerView in einem LinearLayout:

<?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">
    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:scrollbars="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />
</LinearLayout>

Beachten Sie, dass Sie den vollqualifizierten Namen "android.support.v7.widget.RecyclerView " verwenden müssen, da RecyclerView es in einer Supportbibliothek verpackt ist. Die OnCreate Methode der MainActivity Initialisierung dieses Layouts, instanziiert den Adapter und bereitet die zugrunde liegende Datenquelle vor:

public class MainActivity : Activity
{
    RecyclerView mRecyclerView;
    RecyclerView.LayoutManager mLayoutManager;
    PhotoAlbumAdapter mAdapter;
    PhotoAlbum mPhotoAlbum;

    protected override void OnCreate (Bundle bundle)
    {
        base.OnCreate (bundle);

        // Prepare the data source:
        mPhotoAlbum = new PhotoAlbum ();

        // Instantiate the adapter and pass in its data source:
        mAdapter = new PhotoAlbumAdapter (mPhotoAlbum);

        // Set our view from the "main" layout resource:
        SetContentView (Resource.Layout.Main);

        // Get our RecyclerView layout:
        mRecyclerView = FindViewById<RecyclerView> (Resource.Id.recyclerView);

        // Plug the adapter into the RecyclerView:
        mRecyclerView.SetAdapter (mAdapter);

Dieser Code bewirkt Folgendes:

  1. Instanziiert die PhotoAlbum Datenquelle.

  2. Übergibt die Fotoalbumdatenquelle an den Konstruktor des Adapters PhotoAlbumAdapter (die weiter unten in dieser Anleitung definiert ist). Beachten Sie, dass es als bewährte Methode gilt, die Datenquelle als Parameter an den Konstruktor des Adapters zu übergeben.

  3. Ruft das RecyclerView Layout ab.

  4. Plugs the adapter into the RecyclerView instance by calling the RecyclerView SetAdapter method as shown above.

Layout-Manager

Jedes Element besteht RecyclerView aus einem CardView Element, das ein Fotobild und eine Fotobeschriftung enthält (Details werden im Abschnitt "Ansichtshalter " unten behandelt). Das vordefinierte Layout LinearLayoutManager wird verwendet, um jede CardView in einer vertikalen Bildlaufanordnung zu gestalten:

mLayoutManager = new LinearLayoutManager (this);
mRecyclerView.SetLayoutManager (mLayoutManager);

Dieser Code befindet sich in der Methode der Hauptaktivität OnCreate . Der Konstruktor für den Layout-Manager erfordert einen Kontext, sodass der MainActivity Konstruktor wie this oben dargestellt übergeben wird.

Anstatt die vordefinierten LinearLayoutManagerElemente zu verwenden, können Sie einen benutzerdefinierten Layout-Manager anschließen, der zwei CardView Elemente nebeneinander anzeigt und einen Seitendrehanimationseffekt implementiert, um die Sammlung von Fotos zu durchlaufen. Später in dieser Anleitung sehen Sie ein Beispiel für das Ändern des Layouts, indem Sie in einem anderen Layout-Manager wechseln.

Ansichtshalter

Die Ansichtshalterklasse wird aufgerufen PhotoViewHolder. Jede PhotoViewHolder Instanz enthält Verweise auf das ImageView und TextView ein zugeordnetes Zeilenelement, das in einem CardView hier dargestellten Diagramm angeordnet ist:

Diagramm von CardView, das eine ImageView und TextView enthält

PhotoViewHolder abgeleitet von RecyclerView.ViewHolder und enthält Eigenschaften zum Speichern von Verweisen auf das ImageView oben gezeigte Layout TextView . PhotoViewHolder besteht aus zwei Eigenschaften und einem Konstruktor:

public class PhotoViewHolder : RecyclerView.ViewHolder
{
    public ImageView Image { get; private set; }
    public TextView Caption { get; private set; }

    public PhotoViewHolder (View itemView) : base (itemView)
    {
        // Locate and cache view references:
        Image = itemView.FindViewById<ImageView> (Resource.Id.imageView);
        Caption = itemView.FindViewById<TextView> (Resource.Id.textView);
    }
}

In diesem Codebeispiel wird der PhotoViewHolder Konstruktor einen Verweis auf die übergeordnete Elementansicht (die ) übergeben, PhotoViewHolder die CardViewumbrochen wird. Beachten Sie, dass Sie die übergeordnete Elementansicht immer an den Basiskonstruktor weiterleiten. Der PhotoViewHolder Konstruktor ruft FindViewById die übergeordnete Elementansicht auf, um die einzelnen untergeordneten Ansichtsverweise zu finden, ImageView und TextViewspeichert die Ergebnisse in den Image jeweiligen Eigenschaften.Caption Der Adapter ruft später Ansichtsverweise von diesen Eigenschaften ab, wenn diese untergeordneten Ansichten mit neuen Daten aktualisiert CardViewwerden.

Weitere Informationen RecyclerView.ViewHolderfinden Sie in der RecyclerView.ViewHolder-Klassenreferenz.

Adapter

Der Adapter lädt jede RecyclerView Zeile mit Daten für ein bestimmtes Foto. Bei einem bestimmten Foto an Zeilenposition P sucht der Adapter beispielsweise die zugeordneten Daten an Position P innerhalb der Datenquelle und kopiert diese Daten an position P in das Zeilenelement an Position P in der RecyclerView Auflistung. Der Adapter verwendet den Ansichtshalter, um die Verweise für die ImageView und TextView an dieser Position nachzuschlagen, damit diese Ansichten nicht wiederholt aufgerufen FindViewById werden müssen, während der Benutzer durch die Fotosammlung scrollt und Ansichten wiederverwendet.

In RecyclerViewer wird eine Adapterklasse zum Erstellen PhotoAlbumAdapterabgeleitetRecyclerView.Adapter:

public class PhotoAlbumAdapter : RecyclerView.Adapter
{
    public PhotoAlbum mPhotoAlbum;

    public PhotoAlbumAdapter (PhotoAlbum photoAlbum)
    {
        mPhotoAlbum = photoAlbum;
    }
    ...
}

Das mPhotoAlbum Element enthält die Datenquelle (das Fotoalbum), die an den Konstruktor übergeben wird. Der Konstruktor kopiert das Fotoalbum in diese Membervariable. Die folgenden erforderlichen RecyclerView.Adapter Methoden werden implementiert:

  • OnCreateViewHolder – Instanziiert die Elementlayoutdatei und den Ansichtshalter.

  • OnBindViewHolder – Lädt die Daten an der angegebenen Position in die Ansichten, deren Verweise im angegebenen Ansichtshalter gespeichert sind.

  • ItemCount – Gibt die Anzahl der Elemente in der Datenquelle zurück.

Der Layout-Manager ruft diese Methoden auf, während elemente innerhalb des RecyclerViewLayout-Managers positioniert werden. Die Umsetzung dieser Methoden wird in den folgenden Abschnitten untersucht.

OnCreateViewHolder

Der Layout-Manager ruft auf OnCreateViewHolder , wenn der RecyclerView neue Ansichtshalter ein Element darstellt. OnCreateViewHolder Überbläht die Elementansicht aus der Layoutdatei der Ansicht und umschließt die Ansicht in einer neuen PhotoViewHolder Instanz. Der PhotoViewHolder Konstruktor sucht und speichert Verweise auf untergeordnete Ansichten im Layout, wie zuvor in View Holder beschrieben.

Jedes Zeilenelement wird durch ein CardView Element dargestellt, das ein ImageView (für das Foto) und ein TextView (für die Beschriftung) enthält. Dieses Layout befindet sich in der Datei PhotoCardView.axml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:card_view="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content">
    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        card_view:cardElevation="4dp"
        card_view:cardUseCompatPadding="true"
        card_view:cardCornerRadius="5dp">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:padding="8dp">
            <ImageView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/imageView"
                android:scaleType="centerCrop" />
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textAppearance="?android:attr/textAppearanceMedium"
                android:textColor="#333333"
                android:text="Caption"
                android:id="@+id/textView"
                android:layout_gravity="center_horizontal"
                android:layout_marginLeft="4dp" />
        </LinearLayout>
    </android.support.v7.widget.CardView>
</FrameLayout>

Dieses Layout stellt ein einzelnes Zeilenelement in der RecyclerView. Die OnBindViewHolder Methode (unten beschrieben) kopiert Daten aus der Datenquelle in das ImageView und TextView dieses Layout. OnCreateViewHolder überhöht dieses Layout für eine bestimmte Fotoposition in der RecyclerView und instanziiert eine neue PhotoViewHolder Instanz (die Verweise auf die ImageView und TextView untergeordneten Ansichten im zugehörigen CardView Layout findet und zwischenspeichert):

public override RecyclerView.ViewHolder
    OnCreateViewHolder (ViewGroup parent, int viewType)
{
    // Inflate the CardView for the photo:
    View itemView = LayoutInflater.From (parent.Context).
                Inflate (Resource.Layout.PhotoCardView, parent, false);

    // Create a ViewHolder to hold view references inside the CardView:
    PhotoViewHolder vh = new PhotoViewHolder (itemView);
    return vh;
}

Die resultierende Ansichtshalterinstanz , vhwird zurück an den Aufrufer (der Layout-Manager) zurückgegeben.

OnBindViewHolder

Wenn der Layout-Manager bereit ist, eine bestimmte Ansicht im RecyclerViewsichtbaren Bildschirmbereich anzuzeigen, ruft er die Methode des Adapters OnBindViewHolder auf, um das Element an der angegebenen Zeilenposition mit Inhalt aus der Datenquelle auszufüllen. OnBindViewHolder ruft die Fotoinformationen für die angegebene Zeilenposition (bildressource des Fotos und die Zeichenfolge für die Beschriftung des Fotos) ab und kopiert diese Daten in die zugehörigen Ansichten. Ansichten befinden sich über Verweise, die im Ansichtshalterobjekt gespeichert sind (die über den holder Parameter übergeben werden):

public override void
    OnBindViewHolder (RecyclerView.ViewHolder holder, int position)
{
    PhotoViewHolder vh = holder as PhotoViewHolder;

    // Load the photo image resource from the photo album:
    vh.Image.SetImageResource (mPhotoAlbum[position].PhotoID);

    // Load the photo caption from the photo album:
    vh.Caption.Text = mPhotoAlbum[position].Caption;
}

Das übergebene Ansichtshalterobjekt muss zuerst in den abgeleiteten Ansichtshaltertyp (in diesem Fall) umgewandelt werden, PhotoViewHolderbevor es verwendet wird. Der Adapter lädt die Bildressource in die Ansicht, auf die von der Eigenschaft des Ansichtsinhabers verwiesen wird, und kopiert den Beschriftungstext Image in die Ansicht, auf die von der Eigenschaft des Ansichtsinhabers Caption verwiesen wird. Dadurch wird die zugeordnete Ansicht mit ihren Daten gebunden.

Beachten Sie, dass OnBindViewHolder es sich um den Code handelt, der sich direkt mit der Struktur der Daten befasst. In diesem Fall wird erläutert, OnBindViewHolder wie die RecyclerView Elementposition dem zugeordneten Datenelement in der Datenquelle zugeordnet wird. Die Zuordnung ist in diesem Fall einfach, da die Position als Arrayindex in das Fotoalbum verwendet werden kann; Komplexere Datenquellen erfordern jedoch möglicherweise zusätzlichen Code, um eine solche Zuordnung herzustellen.

ItemCount

Die ItemCount Methode gibt die Anzahl der Elemente in der Datensammlung zurück. In der Beispiel-Fotoanzeige-App ist die Elementanzahl die Anzahl der Fotos im Fotoalbum:

public override int ItemCount
{
    get { return mPhotoAlbum.NumPhotos; }
}

Weitere Informationen RecyclerView.Adapterfinden Sie in der Referenz zur RecyclerView.Adapter-Klasse.

Zusammenfassung

Die resultierende RecyclerView Implementierung für die Beispielfoto-App besteht aus MainActivity Code, der die Datenquelle, den Layout-Manager und den Adapter erstellt. MainActivity erstellt die Instanz, instanziiert die mRecyclerView Datenquelle und den Adapter und plugs in den Layout-Manager und Adapter:

public class MainActivity : Activity
{
    RecyclerView mRecyclerView;
    RecyclerView.LayoutManager mLayoutManager;
    PhotoAlbumAdapter mAdapter;
    PhotoAlbum mPhotoAlbum;

    protected override void OnCreate (Bundle bundle)
    {
        base.OnCreate (bundle);
        mPhotoAlbum = new PhotoAlbum();
        SetContentView (Resource.Layout.Main);
        mRecyclerView = FindViewById<RecyclerView> (Resource.Id.recyclerView);

        // Plug in the linear layout manager:
        mLayoutManager = new LinearLayoutManager (this);
        mRecyclerView.SetLayoutManager (mLayoutManager);

        // Plug in my adapter:
        mAdapter = new PhotoAlbumAdapter (mPhotoAlbum);
        mRecyclerView.SetAdapter (mAdapter);
    }
}

PhotoViewHolder sucht und speichert die Ansichtsverweise zwischen:

public class PhotoViewHolder : RecyclerView.ViewHolder
{
    public ImageView Image { get; private set; }
    public TextView Caption { get; private set; }

    public PhotoViewHolder (View itemView) : base (itemView)
    {
        // Locate and cache view references:
        Image = itemView.FindViewById<ImageView> (Resource.Id.imageView);
        Caption = itemView.FindViewById<TextView> (Resource.Id.textView);
    }
}

PhotoAlbumAdapter implementiert die drei erforderlichen Methodenüberschreibungen:

public class PhotoAlbumAdapter : RecyclerView.Adapter
{
    public PhotoAlbum mPhotoAlbum;
    public PhotoAlbumAdapter (PhotoAlbum photoAlbum)
    {
        mPhotoAlbum = photoAlbum;
    }

    public override RecyclerView.ViewHolder
        OnCreateViewHolder (ViewGroup parent, int viewType)
    {
        View itemView = LayoutInflater.From (parent.Context).
                    Inflate (Resource.Layout.PhotoCardView, parent, false);
        PhotoViewHolder vh = new PhotoViewHolder (itemView);
        return vh;
    }

    public override void
        OnBindViewHolder (RecyclerView.ViewHolder holder, int position)
    {
        PhotoViewHolder vh = holder as PhotoViewHolder;
        vh.Image.SetImageResource (mPhotoAlbum[position].PhotoID);
        vh.Caption.Text = mPhotoAlbum[position].Caption;
    }

    public override int ItemCount
    {
        get { return mPhotoAlbum.NumPhotos; }
    }
}

Wenn dieser Code kompiliert und ausgeführt wird, wird die einfache Fotoanzeige-App erstellt, wie in den folgenden Screenshots gezeigt:

Zwei Screenshots der Fotoanzeige-App mit vertikal scrollenden Fotokarten

Wenn Schatten nicht gezeichnet werden (wie im obigen Screenshot dargestellt), bearbeiten Sie Eigenschaften/AndroidManifest.xml , und fügen Sie dem <application> Element die folgende Attributeinstellung hinzu:

android:hardwareAccelerated="true"

Diese einfache App unterstützt nur das Durchsuchen des Fotoalbums. Es reagiert nicht auf Ereignisse mit Elementeingabe und behandelt keine Änderungen in den zugrunde liegenden Daten. Diese Funktionalität wird im Beispiel zum Erweitern des RecyclerView-Beispiels hinzugefügt.

Ändern des LayoutManagers

Aufgrund der RecyclerViewFlexibilität ist es einfach, die App so zu ändern, dass sie einen anderen Layout-Manager verwendet. Im folgenden Beispiel wird es so geändert, dass das Fotoalbum mit einem Rasterlayout angezeigt wird, das horizontal und nicht mit einem vertikalen linearen Layout scrollt. Dazu wird die Instanziierung des Layout-Managers so geändert, dass sie wie GridLayoutManager folgt verwendet wird:

mLayoutManager = new GridLayoutManager(this, 2, GridLayoutManager.Horizontal, false);

Diese Codeänderung ersetzt die Vertikale LinearLayoutManager durch ein GridLayoutManager Raster, das aus zwei Zeilen besteht, die in horizontaler Richtung scrollen. Wenn Sie die App erneut kompilieren und ausführen, sehen Sie, dass die Fotos in einem Raster angezeigt werden und dass der Bildlauf horizontal und nicht vertikal ist:

Beispielfoto der App mit horizontalem Bildlauf von Fotos in einem Raster

Durch Das Ändern einer Codezeile ist es möglich, die Fotoanzeige-App so zu ändern, dass ein anderes Layout mit unterschiedlichem Verhalten verwendet wird. Beachten Sie, dass weder der Adaptercode noch die Layout-XML geändert werden mussten, um die Layoutformatvorlage zu ändern.

Im nächsten Thema wird diese einfache Beispiel-App erweitert, um Elementklickereignisse zu behandeln und zu aktualisierenRecyclerView, wenn sich die zugrunde liegende Datenquelle ändert.