Utiliser le RecyclerView sous Android, première partie

android robot post logoAvec Android 5 Lollipop, Google a proposé un remplaçant des ListView, le RecyclerView. Les avantages de ce widgets sont détaillés dans la documentation. Cette documentation explique également comment mettre en place les différents composants. Le web a également fleuri de tutos sur ce sujet.

Et pourtant, malgré tous les tutos disponibles en ligne, il est extrêmement difficile d’en trouver un qui vous conduise à un résultat utilisable dans la vie réelle. Mettre en place une liste pour qu’un tap sur un élément affiche un Toast est très limité.

Aussi, je vous propose ici un tuto plus complet inspiré de ce qui se fait pour une application mise en production. Pour illustrer le tout, j’utilise l’application Compagnon Alkemy qui contient plusieurs exemples d’actions suite au tap sur un élément. Ma petite valeur ajoutée est que je vous propose ce tuto dans l’ordre dans lequel vous devriez en toute logique penser aux différents composants. Pour rester lisible et structuré, ce tuto sera décomposé en plusieurs billets.

Le RecyclerView dans le compagnon Alkemy

Affichage des factions disponibles dans la version 2 du Compagnon Alkemy.

Affichage des factions disponibles dans la version 2 du Compagnon Alkemy.

Le Compagnon Alkemy est une application du service Brothers in Games. Elle permet aux joueurs du jeu de figurines Alkemy de consulter les informations de profile de toutes les figurines du jeu. Les joueurs perdent ainsi moins de temps à chercher les informations utiles dans les livres de règles.

L’app affiche des listes à différents endroits avec différentes actions associées. Dans ce premier billet traitant du RecyclerView, je vais prendre un élément très simple : l’affichage des factions.

La simplicité est la raison pour laquelle j’ai choisi cette liste. Pour chaque élément, elle n’affiche qu’un champ : le nom de la faction. Un tap sur un élément affiche une nouvelle vue. Dans ce cas, il s’agit d’une nouvelle liste, celle des profiles attachés à la faction, mais le comportement sera identique pour le cas de l’affichage d’un détail.

Configurer le projet

Le RecyclerView et CardView (qui serviront pour l’affichage des éléments) font partie de la bibliothèque de support v7. Vous pouvez donc les utiliser dans des projets Android 4.x. Il faut cependant ajouter la dépendance dans votre fichier Gradle.

dependencies {
    compile 'com.android.support:recyclerview-v7:23.0.1'
    compile 'com.android.support:cardview-v7:23.0.1'
}

Les numéros de version sont évidemment ceux en vigueur à la rédaction de ce billet, mettez les à jour en fonction de votre version.

Définir l’interface

Nous allons afficher une liste d’éléments. Ces éléments sont structurés dans un Layout. Il n’y a rien de nouveau ici sinon que nous allons utiliser une CardView. Les CardView sont en gros des FrameLayout qui peuvent avoir des coins arrondis (défini par card_view:cardCornerRadius) et une ombre portée. Vous pouvez évidemment ne pas les utiliser mais c’est le composant qui permet de respecter au mieux les guidelines de design Android.

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"

    android:id="@+id/card_view"

    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    card_view:cardCornerRadius="5dp"
    card_view:cardUseCompatPadding="true">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:id="@+id/faction_name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal"
            android:text="Faction Default Name" />

    </LinearLayout>
</android.support.v7.widget.CardView>

Ce layout ne présente pas les styles appliqués aux éléments pour une question de lisibilité.

L’affichage des éléments va passer comme pour les ListView par un Adapter. Celui-ci a la charge d’associer un contenu (une donnée) au contenant (les View).

Définir un Adapter

Il faut maintenant définir une classe qui va hériter de RecyclerView.Adapter. Mais je ne vais pas la faire hériter ce cette classe tout de suite… Ce nouvel adapteur va avoir besoin d’une autre classe, un ViewHolder.

Ce nom vous semble familier ? Tout à fait, avec les ListView, il s’agissait du pattern qui permettait d’améliorer les performances en facilitant l’accès aux différents éléments des vues. Le ViewHolder conserve donc les références vers les éléments des vues et évite de les chercher à chaque création d’objet. Si avec les ListView l’usage de ce pattern était optionnel, avec les RecyclerView, vous n’avez plus le choix. Dans notre cas, le ViewHolder va ressembler à ceci :

public static class FactionViewHolder
        extends RecyclerView.ViewHolder {

    TextView factionName;

    public FactionViewHolder(View itemView) {
        super(itemView);

        this.factionName = (TextView) itemView.findViewById(R.id.faction_name);

    }
}

Nous retrouvons une propriété qui décrit notre champ. Cette classe va être définie en tant que classe interne de notre FactionsAdapter qui va maintenant pouvoir être complété.

Vous vous doutez que nous allons manipuler une collection d’objets de type Faction qui va donc être ajoutée ici.

public class FactionsAdapter extends RecyclerView.Adapter<FactionsAdapter.FactionViewHolder> {

    final private List<Faction> factions = new ArrayList<>();

    @Override
    public FactionViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return null;
    }

    @Override
    public void onBindViewHolder(FactionViewHolder holder, int position) {

    }

    @Override
    public int getItemCount() {
        return this.factions.size();
    }

    public static class FactionViewHolder
            extends RecyclerView.ViewHolder {
        ...
}

Je n’ai évidemment pas répété dans ce dernier listing le contenu du ViewHolder.

Trois méthodes doivent être implantés dans la classe fille, vous les voyez dans le listing ci-dessus. Tout comme avec les précédents Adapter, il est judicieux de conserver dans cette classe la collection à afficher. Dans tous les cas, cette collection est initialisée à la création de l’objet. La méthode getItemCount est en conséquence la plus triviale à implanter puisqu’il suffit de retourner la taille de cette collection. Pour les deux autres, ça va être un peu plus compliqué.

La méthode onCreateViewHolder sera appelée lorsque le RecyclerView aura besoin d’un nouveau ViewHolder. Dans notre cas, l’implémentation va être simple.

@Override
public FactionViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.faction_item_card, parent, false);
    Typeface alkemy_font = Typeface.createFromAsset(parent.getContext().getAssets(), "BenjaminFranklin.ttf");
    ((TextView) itemView.findViewById(R.id.tv_faction_name)).setTypeface(alkemy_font);

    return new FactionViewHolder(itemView);
}

La méthode onBindViewHolder est appelée par le RecyclerView lorsqu’il doit afficher un élément à une position donnée. Cette méthode permet de mettre à jour la vue en fonction de l’élément. L’implémentation en elle même peut être très simple, mais c’est évidemment à ce niveau que vous pouvez modifier l’apparence en fonction de la donnée à afficher.

@Override
public void onBindViewHolder(FactionViewHolder holder, int position) {
    Faction f = factions.get(position);

    holder.factionName.setText(f.name());

}

Dans l’état nous avons une implémentation fonctionnelle d’un Adapter. La prochaine étape consistera à afficher la liste (le RecyclerView) et y affecter une action au tap.

Ceci est expliqué dans la seconde partie de ce tuto.

À propos de... Darko Stankovski

iT guy, photographe et papa 3.0, je vous fais partager mon expérience et découvertes dans ces domaines. Vous pouvez me suivre sur les liens ci-dessous.

Vous aimerez aussi...

1 réponse

  1. 19 février 2016

    […] poursuivre mon tuto inspiré de l’application Compagnon Alkemy qui est en production. Dans une première partie, nous avons défini les vues des éléments et l’Adapter, il est temps de passer à […]

Laisser un commentaire