Partager via


Extension de l’exemple RecyclerView

L’application de base décrite dans A Basic RecyclerView Example ne fait pas grand-chose , il fait simplement défiler et affiche une liste fixe d’éléments de photographie pour faciliter la navigation. Dans les applications réelles, les utilisateurs s’attendent à pouvoir interagir avec l’application en appuyant sur des éléments dans l’affichage. En outre, la source de données sous-jacente peut changer (ou être modifiée par l’application), et le contenu de l’affichage doit rester cohérent avec ces modifications. Dans les sections suivantes, vous allez apprendre à gérer les événements de clic d’élément et à mettre à jour RecyclerView lorsque la source de données sous-jacente change.

Gestion des événements Item-Click

Lorsqu’un utilisateur touche un élément dans le RecyclerView, un événement item-click est généré pour notifier l’application à quel élément a été touché. Cet événement n’est pas généré par RecyclerView : à la place, l’affichage d’élément (qui est encapsulé dans le titulaire de la vue) détecte les touches et signale ces touches en tant qu’événements de clic.

Pour illustrer comment gérer les événements de clic d’élément, les étapes suivantes expliquent comment l’application d’affichage photo de base est modifiée pour signaler la photographie qui a été touchée par l’utilisateur. Lorsqu’un événement item-click se produit dans l’exemple d’application, la séquence suivante se produit :

  1. La photo détecte l’événement item-click et avertit l’adaptateur CardView .

  2. L’adaptateur transfère l’événement (avec des informations de position d’élément) au gestionnaire de clics d’élément de l’activité.

  3. Le gestionnaire de clics d’élément de l’activité répond à l’événement item-click.

Tout d’abord, un membre de gestionnaire d’événements appelé ItemClick est ajouté à la définition de PhotoAlbumAdapter classe :

public event EventHandler<int> ItemClick;

Ensuite, une méthode de gestionnaire d’événements item-click est ajoutée à MainActivity. Ce gestionnaire affiche brièvement un toast qui indique quel élément de photographie a été touché :

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

Ensuite, une ligne de code est nécessaire pour inscrire le OnItemClick gestionnaire auprès PhotoAlbumAdapterde . Un bon endroit pour le faire est immédiatement après PhotoAlbumAdapter la création :

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

Dans cet exemple de base, l’inscription de gestionnaires a lieu dans la méthode de l’activité principale, mais une application de OnCreate production peut inscrire le gestionnaire dans OnResume et l’annuler OnPause . Pour plus d’informations, consultez cycle de vie de l’activité.

PhotoAlbumAdapter appellera OnItemClick maintenant lorsqu’il reçoit un événement item-click. L’étape suivante consiste à créer un gestionnaire dans l’adaptateur qui déclenche cet ItemClick événement. La méthode suivante est OnClickajoutée immédiatement après la méthode de l’adaptateur ItemCount :

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

Cette OnClick méthode est l’écouteur de l’adaptateur pour les événements de clic d’élément à partir d’affichages d’éléments. Avant que cet écouteur puisse être inscrit avec un affichage d’élément (via le titulaire d’affichage de l’affichage de l’élément), le PhotoViewHolder constructeur doit être modifié pour accepter cette méthode en tant qu’argument supplémentaire et s’inscrire OnClick auprès de l’événement d’affichage Click d’élément. Voici le constructeur modifié 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);
}

Le itemView paramètre contient une référence à celle CardView qui a été touchée par l’utilisateur. Notez que la classe de base du titulaire d’affichage connaît la position de disposition de l’élément (CardView) qu’elle représente (via la LayoutPosition propriété) et que cette position est passée à la méthode de OnClick l’adaptateur lorsqu’un événement item-click a lieu. La méthode de l’adaptateur OnCreateViewHolder est modifiée pour passer la méthode de OnClick l’adaptateur au constructeur du titulaire d’affichage :

PhotoViewHolder vh = new PhotoViewHolder (itemView, OnClick);

Maintenant, lorsque vous créez et exécutez l’exemple d’application d’affichage de photos, l’appui sur une photo dans l’affichage entraîne l’affichage d’un toast indiquant que la photographie a été touchée :

Exemple de toast qui s’affiche lorsqu’une carte photo est tapée

Cet exemple illustre une seule approche pour l’implémentation de gestionnaires d’événements avec RecyclerView. Une autre approche qui pourrait être utilisée ici consiste à placer des événements sur le titulaire de la vue et que l’adaptateur s’abonne à ces événements. Si l’exemple d’application photo a fourni une fonctionnalité d’édition de photos, des événements distincts seraient nécessaires pour les ImageView éléments suivants CardViewTextView : touches sur la TextView boîte de dialogue lancerait une EditView boîte de dialogue qui permet à l’utilisateur de modifier le légende et touche le ImageView lancement d’un outil tactile photo qui permet à l’utilisateur de rogner ou de faire pivoter la photo. Selon les besoins de votre application, vous devez concevoir la meilleure approche pour gérer et répondre aux événements tactiles.

Pour montrer comment RecyclerView mettre à jour lorsque le jeu de données change, l’exemple d’application d’affichage de photos peut être modifié de manière aléatoire pour choisir une photo dans la source de données et la permuter avec la première photo. Tout d’abord, un bouton Sélection aléatoire est ajouté à l’exemple de disposition Main.axml de l’application photo :

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

Ensuite, le code est ajouté à la fin de la méthode de l’activité OnCreate principale pour localiser le Random Pick bouton dans la disposition et y attacher un gestionnaire :

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

Ce gestionnaire appelle la méthode de RandomSwap l’album photo lorsque le bouton Sélection aléatoire est appuyé. La RandomSwap méthode échange aléatoirement une photo avec la première photo de la source de données, puis retourne l’index de la photo permutée de façon aléatoire. Lorsque vous compilez et exécutez l’exemple d’application avec ce code, l’appui sur le bouton Sélection aléatoire n’entraîne pas de modification d’affichage, car il RecyclerView n’est pas conscient de la modification apportée à la source de données.

Pour conserver RecyclerView la mise à jour après les modifications de la source de données, le gestionnaire de clic sélection aléatoire doit être modifié pour appeler la méthode de NotifyItemChanged l’adaptateur pour chaque élément de la collection qui a changé (dans ce cas, deux éléments ont changé : la première photo et la photo permutée). Cela entraîne RecyclerView la mise à jour de son affichage afin qu’il soit cohérent avec le nouvel état de la source de données :

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

Maintenant, lorsque le bouton Sélection aléatoire est appuyé, RecyclerView met à jour l’affichage pour montrer qu’une photo plus bas dans la collection a été échangée avec la première photo de la collection :

Première capture d’écran avant l’échange, deuxième capture d’écran après l’échange

Bien sûr, NotifyDataSetChanged aurait pu être appelé au lieu d’effectuer les deux appels à NotifyItemChanged, mais cela forcerait RecyclerView à actualiser l’ensemble de la collection même si seulement deux éléments de la collection avaient changé. L’appel NotifyItemChanged est beaucoup plus efficace que l’appel NotifyDataSetChanged.