1. Avant de commencer
Réfléchissez un instant aux applications que vous utilisez fréquemment sur votre téléphone. Presque toutes disposent d'au moins une liste. L'écran de l'historique des appels, l'application Contacts et votre application de réseaux sociaux préférée affichent tous une liste de données. Comme le montre la capture d'écran ci-dessous, certaines de ces applications affichent une simple liste de mots ou d'expressions, tandis que d'autres affichent des éléments plus complexes, tels que des fiches contenant du texte et des images. Quel que soit le contenu, l'affichage d'une liste de données est l'une des tâches d'UI les plus courantes dans Android.
Android fournit RecyclerView
pour vous aider à créer des applications avec des listes. RecyclerView
garantit une efficacité optimale, même avec de longues listes, grâce à la réutilisation (ou au recyclage) des vues qui ne sont plus affichées à l'écran. Lorsqu'un élément de liste n'est plus affiché à l'écran, RecyclerView
réutilise cette vue pour l'élément suivant sur le point d'être affiché. Cela signifie que l'élément affiche le nouveau contenu qui défile à l'écran. Ce comportement RecyclerView
vous fait gagner beaucoup de temps de traitement et garantit un défilement plus fluide des listes.
Dans la séquence ci-dessous, vous pouvez voir que les données ABC
ont été affichées dans une vue. Une fois que cette vue est sortie de l'écran, RecyclerView
la réutilise pour les nouvelles données, XYZ
.
Dans cet atelier de programmation, vous allez créer l'application Affirmations. Il s'agit d'une application simple qui affiche dix affirmations positives sous forme de texte dans une liste déroulante. Ensuite, dans l'atelier de suivi, vous ajouterez une image inspirante à chaque affirmation et vous peaufinerez l'interface utilisateur de l'application.
Conditions préalables
- Créer un projet à partir d'un modèle dans Android Studio.
- Ajouter des ressources de chaîne à une application.
- Définir une mise en page au format XML.
- Comprendre les classes et l'héritage dans le langage Kotlin (y compris les classes abstraites).
- Hériter d'une classe existante et remplacer ses méthodes.
- Utiliser la documentation disponible sur developer.android.com pour les cours fournis par le framework Android.
Points abordés
- Comment utiliser un
RecyclerView
pour afficher une liste de données. - Comment organiser votre code dans des packages.
- Comment utiliser des adaptateurs avec
RecyclerView
pour personnaliser l'apparence d'un élément de liste.
Objectifs de l'atelier
- Application qui affiche une liste de chaînes d'affirmation à l'aide d'un
RecyclerView
.
Ce dont vous avez besoin
- Un ordinateur équipé d'Android Studio version 4.1 ou ultérieure.
2. Créer le projet
Créer un projet "Activité vide"
Avant de créer un projet, assurez-vous d'utiliser Android Studio 4.1 ou version ultérieure.
- Démarrez un nouveau projet Kotlin dans Android Studio à l'aide du modèle Activité vide.
- Saisissez Affirmations comme nom de l'application, com.example.affirmations comme nom de package, puis sélectionnez API niveau 19 en tant que version minimale du SDK.
- Cliquez sur Terminer pour créer le projet.
3. Configurer la liste de données
L'étape suivante du processus de création de l'application Affirmations consiste à ajouter des ressources. Vous allez ajouter les éléments suivants à votre projet.
- Des ressources de chaîne à afficher comme affirmations dans l'application.
- Une source de données pour fournir une liste d'affirmations à votre application.
Ajouter des chaînes d'affirmation
- Dans la fenêtre Projet, ouvrez le fichier app > res > values > strings.xml. Actuellement, ce fichier ne contient qu'une seule ressource, à savoir le nom de l'application.
- Dans
strings.xml
, ajoutez les affirmations suivantes en tant que ressources de chaîne individuelles. Nommez-lesaffirmation1
,affirmation2
, etc.
Texte des affirmations
I am strong. I believe in myself. Each day is a new opportunity to grow and be a better version of myself. Every challenge in my life is an opportunity to learn from. I have so much to be grateful for. Good things are always coming into my life. New opportunities await me at every turn. I have the courage to follow my heart. Things will unfold at precisely the right time. I will be present in all the moments that this day brings.
Une fois que vous avez terminé, le fichier strings.xml
doit se présenter comme suit.
<resources>
<string name="app_name">Affirmations</string>
<string name="affirmation1">I am strong.</string>
<string name="affirmation2">I believe in myself.</string>
<string name="affirmation3">Each day is a new opportunity to grow and be a better version of myself.</string>
<string name="affirmation4">Every challenge in my life is an opportunity to learn from.</string>
<string name="affirmation5">I have so much to be grateful for.</string>
<string name="affirmation6">Good things are always coming into my life.</string>
<string name="affirmation7">New opportunities await me at every turn.</string>
<string name="affirmation8">I have the courage to follow my heart.</string>
<string name="affirmation9">Things will unfold at precisely the right time.</string>
<string name="affirmation10">I will be present in all the moments that this day brings.</string>
</resources>
Maintenant que vous avez ajouté des ressources de chaîne, vous pouvez les référencer dans votre code en tant que R.string.affirmation1
ou R.string.affirmation2
.
Créer un package
En organisant votre code de manière logique, vous et d'autres développeurs pouvez le comprendre, le gérer et l'étendre. À l'instar des documents, que vous pouvez organiser en fichiers et dossiers, vous pouvez organiser votre code en fichiers et packages.
Qu'est-ce qu'un package ?
- Dans la fenêtre Project (Projet) (Android) d'Android Studio, examinez les nouveaux fichiers de projet sous app > java pour l'application Affirmations. Ils doivent ressembler à la capture d'écran ci-dessous qui présente trois packages : un pour votre code (com.example.affirmations) et deux pour les fichiers de test (com.example.affirmations (androidTest) et com.example.affirmations (test)).
- Notez que le nom du package comprend plusieurs mots séparés par un point.
Vous pouvez utiliser les packages de deux façons.
- Créer différents packages pour les différentes parties de votre code. Par exemple, les développeurs séparent souvent dans des packages différents les classes qui utilisent des données de celles qui créent l'UI.
- Utiliser le code d'autres packages. Pour utiliser les classes d'autres packages, vous devez les définir dans les dépendances de votre système de compilation. Vous pouvez également les importer (instruction
import
) dans votre code afin de pouvoir utiliser leurs noms abrégés (par exemple,TextView
) au lieu de leurs noms complets (par exemple,android.widget.TextView
). Par exemple, vous avez déjà utilisé des instructionsimport
pour des classes telles quesqrt
(import kotlin.math.sqrt
) etView
(import android.view.View
).
Dans l'application Affirmations, en plus d'importer les classes Android et Kotlin, vous allez organiser votre application dans plusieurs packages. Même si votre application ne contient pas beaucoup de classes, il est recommandé d'utiliser des packages pour les regrouper par fonctionnalité.
Nommer des packages
Vous pouvez attribuer n'importe quel nom à un package, pour autant qu'il soit unique. En d'autres termes, aucun autre package publié ne peut porter le même nom. Compte tenu du très grand nombre de packages, et de la difficulté de trouver des noms uniques et aléatoires, les programmeurs utilisent des conventions pour faciliter la création et la compréhension des noms de package.
- La structure du nom de package va du niveau général au plus spécifique. Chaque partie du nom est en minuscules et séparée par un point. Important : le point fait simplement partie du nom. Cela n'indique pas une hiérarchie dans le code et n'impose pas une structure de dossiers.
- Les domaines Internet sont uniques à l'échelle mondiale. Par convention, on utilise donc un domaine, généralement le vôtre ou celui de votre entreprise, comme première partie du nom.
- Vous pouvez choisir les noms des packages pour indiquer ce qu'ils contiennent, ainsi que les relations qu'ils entretiennent.
- Pour les exemples de code tels que celui-ci, on utilise généralement
com.example
suivi du nom de l'application.
Voici quelques exemples de noms de packages prédéfinis et de leur contenu :
kotlin.math
: constantes et fonctions mathématiques.android.widget
: vues, par exempleTextView
.
Créer un package
- Dans le volet Projet d'Android Studio, effectuez un clic droit sur app > java > com.example.affirmations, puis sélectionnez Nouveau > Package.
- Dans le pop-up Nouveau package, notez le préfixe du nom de package suggéré. La première partie est le nom du package sur lequel vous avez effectué un clic droit. Bien que les noms de package ne créent pas de hiérarchie de packages, des parties du nom sont réutilisées pour indiquer une relation et une organisation du contenu.
- Dans le pop-up, ajoutez model à la fin du nom de package suggéré. Les développeurs utilisent souvent model comme nom de package pour les classes qui modélisent (ou représentent) les données.
- Appuyez sur Entrée. Un package est créé sous le package com.example.affirmations (racine). Ce nouveau package contiendra toutes les classes liées aux données définies dans votre application.
Créer la classe de données Affirmation
Dans cette tâche, vous allez créer une classe appelée Affirmation.
Une instance d'objet de Affirmation
représente une affirmation et contient l'ID de ressource de la chaîne avec l'affirmation en question.
- Effectuez un clic droit sur le package com.example.affirmations.model, puis sélectionnez Nouveau > Fichier/Classe Kotlin.
- Dans le pop-up, sélectionnez Classe, puis saisissez
Affirmation
comme nom de classe. Cette opération crée un fichier nomméAffirmation.kt
dans le packagemodel
. - Transformez
Affirmation
en classe de données en ajoutant le mot clédata
avant la définition de classe. Vous obtiendrez une erreur, car au moins une propriété doit être définie pour les classes de données.
Affirmation.kt
package com.example.affirmations.model
data class Affirmation {
}
Lorsque vous créez une instance de Affirmation
, vous devez transmettre l'ID de ressource de la chaîne d'affirmation. L'ID de ressource est un entier.
- Ajoutez un paramètre d'entier
val
stringResourceId
au constructeur de la classeAffirmation
. Cela permet d'éliminer l'erreur.
package com.example.affirmations.model
data class Affirmation(val stringResourceId: Int)
Créer une classe en tant que source de données
Les données affichées dans votre application peuvent provenir de différentes sources (par exemple, de votre projet d'application ou d'une source externe qui nécessite une connexion à Internet pour télécharger des données). Par conséquent, il se peut que les données ne soient pas exactement au format dont vous avez besoin. Le reste de l'application ne doit pas se préoccuper de la provenance ni du format d'origine des données. Vous pouvez (et c'est même conseillé) dissimuler cette préparation de données dans une classe Datasource
distincte qui prépare les données pour l'application.
La préparation des données étant un problème distinct, placez la classe Datasource
dans un package data séparé.
- Dans la fenêtre Projet d'Android Studio, effectuez un clic droit sur app > java > com.example.affirmations, puis sélectionnez Nouveau > Package.
- Saisissez
data
comme dernière partie du nom du package. - Effectuez un clic droit sur le package
data
, puis sélectionnez Nouveau fichier/Nouvelle classe Kotlin. - Saisissez
Datasource
comme nom de classe. - Dans la classe
Datasource
, créez une fonction appeléeloadAffirmations()
.
La fonction loadAffirmations()
doit renvoyer une liste d'Affirmations
. Pour ce faire, créez une liste et insérez-y une instance Affirmation
pour chaque chaîne de ressource.
- Déclarez
List<Affirmation>
comme type renvoyé de la méthodeloadAffirmations()
. - Dans le corps de
loadAffirmations()
, ajoutez une instructionreturn
. - Après le mot clé
return
, appelezlistOf<>()
pour créer uneList
. - Entre les chevrons
<>
, indiquez le type des éléments de liste en tant queAffirmation
. Si nécessaire, importezcom.example.affirmations.model.Affirmation
. - Entre parenthèses, créez une
Affirmation
en transmettantR.string.affirmation1
comme ID de ressource, comme indiqué ci-dessous.
Affirmation(R.string.affirmation1)
- Ajoutez les objets
Affirmation
restants à la liste de toutes les affirmations, en les séparant par des virgules. Une fois terminé, le code doit se présenter comme suit.
Datasource.kt
package com.example.affirmations.data
import com.example.affirmations.R
import com.example.affirmations.model.Affirmation
class Datasource {
fun loadAffirmations(): List<Affirmation> {
return listOf<Affirmation>(
Affirmation(R.string.affirmation1),
Affirmation(R.string.affirmation2),
Affirmation(R.string.affirmation3),
Affirmation(R.string.affirmation4),
Affirmation(R.string.affirmation5),
Affirmation(R.string.affirmation6),
Affirmation(R.string.affirmation7),
Affirmation(R.string.affirmation8),
Affirmation(R.string.affirmation9),
Affirmation(R.string.affirmation10)
)
}
}
[Facultatif] Afficher la taille de la liste Affirmations dans un élément TextView
Pour vérifier que vous pouvez créer une liste d'affirmations, vous pouvez appeler loadAffirmations()
et afficher la taille de la liste d'affirmations renvoyée dans le TextView
fourni avec votre modèle d'application "Activité vide".
- Dans
layouts/activity_main.xml
, attribuez l'id
detextview
auTextView
fourni avec votre modèle. - Dans
MainActivity
, dans la méthodeonCreate()
située après le code existant, obtenez une référence àtextview
.
val textView: TextView = findViewById(R.id.textview)
- Ajoutez ensuite du code pour créer et afficher la taille de la liste des affirmations. Créez un
Datasource
, appelezloadAffirmations()
, obtenez la taille de la liste renvoyée, convertissez-la en chaîne et affectez-la en tant quetext
detextView
.
textView.text = Datasource().loadAffirmations().size.toString()
- Exécutez votre application. Vous devriez alors obtenir l'écran ci-dessous.
- Supprimez le code que vous venez d'ajouter dans
MainActivity
.
4. Ajouter une RecyclerView à votre application
Dans cette tâche, vous allez configurer une RecyclerView
de manière à afficher la liste Affirmations
.
La création et l'utilisation d'une RecyclerView
reposent sur un certain nombre d'éléments. On peut les considérer comme une division du travail. Le schéma ci-dessous vous donne une vue d'ensemble. Vous en apprendrez davantage sur chaque élément au fur et à mesure de l'implémentation.
- élément : élément de données de la liste à afficher. Représente un objet
Affirmation
de votre application. - Adaptateur : accepte les données et les prépare pour que
RecyclerView
les affiche. - ViewHolders : pool de vues que
RecyclerView
peut utiliser et réutiliser pour afficher des affirmations. - RecyclerView : vues affichées à l'écran.
Ajouter une RecyclerView à la mise en page
L'application Affirmations comporte une seule activité nommée MainActivity
et son fichier de mise en page s'appelle activity_main
.xml
. Tout d'abord, vous devez ajouter RecyclerView
à la mise en page de MainActivity
.
- Ouvrez
activity_main.xml
(app > res > layouts > activity_main.xml). - Si ce n'est pas encore le cas, passez en vue fractionnée.
- Supprimez la
TextView
.
La mise en page actuelle utilise ConstraintLayout
. Particulièrement flexible, ConstraintLayout
est la solution idéale lorsque vous souhaitez positionner plusieurs vues enfants dans une mise en page. Étant donné que votre mise en page ne comporte qu'une seule vue enfant, RecyclerView
, vous pouvez basculer vers un ViewGroup
plus simple, appelé FrameLayout
, qui doit être utilisé pour contenir une seule vue enfant.
- Dans le code XML, remplacez
ConstraintLayout
parFrameLayout
. La mise en page doit se présenter comme suit.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
</FrameLayout>
- Passez à la vue Conception.
- Dans la Palette, sélectionnez Conteneurs, puis recherchez RecyclerView.
- Faites glisser une vue RecyclerView dans la mise en page.
- Si le pop-up Ajouter une dépendance de projet s'affiche, lisez-le, puis cliquez sur OK. (Si le pop-up ne s'affiche pas, aucune action n'est requise.)
- Attendez qu'Android Studio ait terminé et que la
RecyclerView
s'affiche dans votre mise en page. - Si nécessaire, remplacez les attributs
layout_width
etlayout_height
de laRecyclerView
parmatch_parent
pour que laRecyclerView
puisse remplir l'intégralité de l'écran. - Définissez l'ID de ressource de
RecyclerView
surrecycler_view
.
RecyclerView
permet d'afficher des éléments de différentes manières ; sous la forme d'une liste linéaire ou d'une grille, par exemple. La disposition des éléments est gérée par un LayoutManager
. Le framework Android fournit des gestionnaires de mise en page pour des mises en page d'éléments de base. L'application Affirmations affiche les éléments sous la forme d'une liste verticale, ce qui vous permet d'utiliser le LinearLayoutManager
.
- Revenez à la vue Code. Dans l'élément
RecyclerView
du code XML, ajoutezLinearLayoutManager
en tant qu'attribut de gestionnaire de mise en page de laRecyclerView
, comme indiqué ci-dessous.
app:layoutManager="LinearLayoutManager"
Pour qu'il soit possible de faire défiler une liste verticale d'éléments plus longue que l'écran, vous devez ajouter une barre de défilement verticale.
- Dans
RecyclerView
, ajoutez un attributandroid:scrollbars
défini survertical
.
android:scrollbars="vertical"
La mise en page XML finale doit ressembler à ceci :
activity_main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
app:layoutManager="LinearLayoutManager" />
</FrameLayout>
- Exécutez votre application.
Le projet doit normalement être compilé et exécuté sans problème. Toutefois, seul un arrière-plan blanc s'affiche dans votre application, car il vous manque un extrait de code essentiel. Pour l'instant, vous disposez de la source de données et de la RecyclerView
qui a été ajoutée à votre mise en page. Cependant, la RecyclerView
ne possède aucune information quant à la façon d'afficher les objets Affirmation
.
Implémenter un adaptateur pour RecyclerView
Votre application doit pouvoir récupérer les données de Datasource
et les mettre en forme, de sorte que chaque Affirmation
puisse être affichée en tant qu'élément dans RecyclerView
.
L'adaptateur est un schéma de conception qui transforme les données en un élément utilisable par RecyclerView
. Dans le cas présent, vous avez besoin d'un adaptateur qui récupère une instance Affirmation
de la liste renvoyée par loadAffirmations()
et la transforme en une vue d'élément de liste, de sorte qu'elle puisse être affichée dans RecyclerView.
.
Lorsque vous exécutez l'application, RecyclerView
utilise l'adaptateur pour déterminer comment afficher vos données à l'écran. RecyclerView
demande à l'adaptateur de créer une vue d'élément de liste pour le premier élément de données de la liste. Une fois la vue obtenue, il demande à l'adaptateur de fournir les données nécessaires pour dessiner l'élément. Ce processus se répète jusqu'à ce que RecyclerView
n'ait plus besoin de vues pour remplir l'écran. Si seulement trois vues d'éléments de liste peuvent être affichées en même temps à l'écran, RecyclerView
demande à l'adaptateur de ne préparer que ces trois vues (au lieu des 10 prévues).
Au cours de cette étape, vous allez créer un adaptateur qui adapte une instance d'objet Affirmation
pour qu'elle puisse être affichée dans RecyclerView
.
Créer l'adaptateur
Un adaptateur se compose de plusieurs parties. De plus, le code que vous allez écrire sera, en grande partie, plus complexe que celui que vous avez rédigé jusqu'à présent. Ne vous inquiétez pas si vous ne comprenez pas immédiatement tous les détails. Une fois que vous aurez terminé cette application avec une RecyclerView
, vous comprendrez mieux comment toutes les parties s'intègrent les unes aux autres. Vous pourrez également réutiliser ce code comme base pour les prochaines applications que vous créerez avec une RecyclerView
.
Créer une mise en page pour les éléments
Chaque élément de la RecyclerView
possède sa propre mise en page, que vous définissez dans un fichier distinct. Étant donné que vous afficherez uniquement une chaîne, vous pouvez utiliser une TextView
pour la mise en page de votre élément.
- Dans res > layouts, créez un fichier vide nommé
list_item.xml
. - Ouvrez
list_item.xml
dans la vue Code. - Ajoutez une
TextView
avecid
item_title
. - Ajoutez
wrap_content
pourlayout_width
etlayout_height
, comme indiqué dans le code ci-dessous.
Notez qu'il n'est pas nécessaire d'utiliser un ViewGroup
autour de votre mise en page, car cette mise en page d'élément de liste sera, par la suite, gonflée et ajoutée en tant qu'enfant à l'élément RecyclerView
parent.
list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/item_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
Vous pouvez également utiliser Fichier > Nouveau > Fichier de ressources de mise en page, en indiquant list_item.xml
dans le champ Nom de fichier et TextView
dans le champ Élément racine. Ensuite, mettez à jour le code généré pour qu'il corresponde au code ci-dessus.
Créer une classe ItemAdapter
- Dans le volet Projet d'Android Studio, effectuez un clic droit sur app > java > com.example.affirmations, puis sélectionnez Nouveau > Package.
- Saisissez
adapter
comme dernière partie du nom du package. - Effectuez un clic droit sur le package
adapter
, puis sélectionnez Nouveau > Fichier/Classe Kotlin. - Saisissez
ItemAdapter
comme nom de classe, terminez l'opération et le fichierItemAdapter.kt
s'ouvre.
Vous devez ajouter un paramètre au constructeur de ItemAdapter
afin de pouvoir transmettre la liste d'affirmations à l'adaptateur.
- Ajoutez au constructeur
ItemAdapter
un paramètreval
nommédataset
, de typeList<Affirmation>
. Si nécessaire, importezAffirmation
. - Étant donné que le
dataset
ne sera utilisé que dans cette classe, définissez-le surprivate
.
ItemAdapter.kt
import com.example.affirmations.model.Affirmation
class ItemAdapter(private val dataset: List<Affirmation>) {
}
ItemAdapter
a besoin d'informations sur la façon de résoudre les ressources de chaîne. Ces informations, ainsi que d'autres concernant l'application, sont stockées dans une instance d'objet Context
que vous pouvez transmettre à une instance ItemAdapter
.
- Ajoutez au constructeur
ItemAdapter
un paramètreval
nommécontext
, de typeContext
. Positionnez-le comme premier paramètre du constructeur.
class ItemAdapter(private val context: Context, private val dataset: List<Affirmation>) {
}
Créer un Viewholder
RecyclerView
n'interagit pas directement avec les vues d'élément, mais traite plutôt avec ViewHolders
. Un ViewHolder
représente une vue d'élément de liste unique dans RecyclerView
et peut être réutilisée lorsque cela s'avère possible. Une instance ViewHolder
contient des références à chacune des vues d'une mise en page d'élément de liste (d'où son nom qui signifie "conteneur de vues"). Il est ainsi plus facile de mettre à jour la vue d'élément de liste avec de nouvelles données. Les conteneurs de vues ajoutent également des informations qui sont utilisées par RecyclerView
pour déplacer efficacement des vues sur l'écran.
- Dans la classe
ItemAdapter
, avant l'accolade fermante pourItemAdapter
, créez une classeItemViewHolder
.
class ItemAdapter(private val context: Context, private val dataset: List<Affirmation>) {
class ItemViewHolder()
}
- Lorsque vous définissez une classe à l'intérieur d'une autre, on parle de création d'une classe imbriquée.
- Étant donné que
ItemViewHolder
n'est utilisé que parItemAdapter
, le fait de le créer à l'intérieur deItemAdapter
montre cette relation. Cette opération est facultative, mais elle permet aux autres développeurs de comprendre la structure de votre programme.
- Ajoutez une
private
val
view
de typeView
en tant que paramètre au constructeur de classeItemViewHolder
. - Définissez
ItemViewHolder
comme sous-classe deRecyclerView.ViewHolder
et transmettez le paramètreview
au constructeur de super-classe. - Dans
ItemViewHolder
, définissez une propriétéval
textView
de typeTextView
. Attribuez-lui la vue avec l'IDitem_title
que vous avez défini danslist_item
.xml
.
class ItemAdapter(private val context: Context, private val dataset: List<Affirmation>) {
class ItemViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
val textView: TextView = view.findViewById(R.id.item_title)
}
}
Remplacer les méthodes d'adaptateur
- Ajoutez le code pour étendre votre
ItemAdapter
à partir de la classe abstraiteRecyclerView.Adapter
. IndiquezItemAdapter.ItemViewHolder
comme type de conteneur de vues entre chevrons.
class ItemAdapter(
private val context: Context,
private val dataset: List<Affirmation>
) : RecyclerView.Adapter<ItemAdapter.ItemViewHolder>() {
class ItemViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
val textView: TextView = view.findViewById(R.id.item_title)
}
}
Une erreur s'affiche, car vous devez implémenter des méthodes abstraites à partir de RecyclerView.Adapter
.
- Placez votre curseur sur
ItemAdapter
et appuyez sur Commande+I (Ctrl+I sous Windows). La liste des méthodes à implémenter (getItemCount()
,onCreateViewHolder()
etonBindViewHolder()
) est affichée.
- Sélectionnez les trois fonctions en utilisant Maj+clic, puis cliquez sur OK.
Des bouchons sont alors créés avec les paramètres appropriés pour les trois méthodes, comme indiqué ci-dessous.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {
TODO("Not yet implemented")
}
override fun getItemCount(): Int {
TODO("Not yet implemented")
}
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
TODO("Not yet implemented")
}
Il ne devrait plus y avoir d'erreurs. Vous devez ensuite implémenter ces méthodes afin qu'elles fonctionnent correctement pour votre application.
Implémenter getItemCount()
La méthode getItemCount()
doit renvoyer la taille de votre ensemble de données. Les données de votre application se trouvent dans la propriété dataset
que vous transmettez au constructeur ItemAdapter
. Vous pouvez obtenir leur taille avec size
.
- Remplacez
getItemCount()
par le code suivant :
override fun getItemCount() = dataset.size
Il s'agit d'une manière plus concise d'écrire ceci :
override fun getItemCount(): Int {
return dataset.size
}
Implémenter onCreateViewHolder()
La méthode onCreateViewHolder()
est appelée par le gestionnaire de mises en page afin de créer des conteneurs de vues pour la RecyclerView
(s'il n'existe aucun conteneur de vues pouvant être réutilisé). N'oubliez pas qu'un conteneur de vues représente une seule vue d'élément de liste.
La méthode onCreateViewHolder()
utilise deux paramètres et renvoie un nouveau ViewHolder
.
- Un paramètre
parent
, qui est le groupe de vues auquel la nouvelle vue d'élément de liste sera associée en tant qu'enfant. La vue parente est laRecyclerView
. - Un paramètre
viewType
, qui devient important lorsqu'une mêmeRecyclerView
contient plusieurs types de vue d'élément. Si différentes mises en page d'élément de liste sont affichées dans laRecyclerView
, il existe différents types de vue d'élément. Vous ne pouvez recycler que des vues d'élément ayant le même type. Dans votre cas, il n'existe qu'une seule mise en page d'élément de liste et un seul type de vue d'élément. Vous ne devez donc pas vous soucier de ce paramètre.
- Dans la méthode
onCreateViewHolder()
, obtenez une instance deLayoutInflater
à partir du contexte fourni (context
duparent
). Le système de gonflage de mise en page sait comment gonfler une mise en page XML dans une hiérarchie d'objets de vue.
val adapterLayout = LayoutInflater.from(parent.context)
- Une fois que vous disposez d'une instance d'objet
LayoutInflater
, ajoutez un point suivi d'un autre appel de méthode pour gonfler la vue d'élément de liste. Transmettez l'ID de ressource de mise en page XMLR.layout.list_item
et le groupe de vuesparent
. Le troisième argument booléen estattachToRoot
. Cet argument doit êtrefalse
, carRecyclerView
ajoute automatiquement cet élément à la hiérarchie des vues le moment venu.
val adapterLayout = LayoutInflater.from(parent.context)
.inflate(R.layout.list_item, parent, false)
adapterLayout
contient désormais une référence à la vue de l'élément de liste (dans laquelle nous trouverons par la suite
des vues enfants telles que la TextView
).
- Dans
onCreateViewHolder()
, renvoyez une nouvelle instanceItemViewHolder
où la vue racine estadapterLayout
.
return ItemViewHolder(adapterLayout)
Voici le code qui a été écrit jusqu'ici pour onCreateViewHolder()
.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {
// create a new view
val adapterLayout = LayoutInflater.from(parent.context)
.inflate(R.layout.list_item, parent, false)
return ItemViewHolder(adapterLayout)
}
Implémenter onBindViewHolder()
La dernière méthode que vous devez remplacer est onBindViewHolder()
. Cette méthode est appelée par le gestionnaire de mise en page afin de remplacer le contenu d'une vue d'élément de liste.
La méthode onBindViewHolder()
comporte deux paramètres : un ItemViewHolder
créé précédemment par la méthode onCreateViewHolder()
et un int
représentant la position
actuelle de l'élément dans la liste. Cette méthode vous permet de trouver l'objet Affirmation
approprié dans l'ensemble de données en fonction de la position.
- Dans
onBindViewHolder()
, créez unval
item
et récupérez l'élément au niveau de laposition
indiquée dans ledataset
.
val item = dataset[position]
Enfin, vous devez mettre à jour toutes les vues référencées par le conteneur de vues afin de tenir compte des données correctes pour cet élément. Dans le cas présent, il n'y a qu'une seule vue : TextView
dans ItemViewHolder
. Définissez le texte de TextView
pour afficher la chaîne Affirmation
de cet élément.
- Vous pouvez, avec une instance d'objet
Affirmation
, trouver l'ID de ressource de chaîne correspondant en appelantitem.stringResourceId
. Toutefois, il s'agit d'un entier et vous devez trouver la correspondance avec la valeur de chaîne réelle.
Dans le framework Android, vous pouvez appeler getString()
avec un ID de ressource de chaîne pour renvoyer la valeur de chaîne qui y est associée. getString()
est une méthode de la classe Resources
. Vous pouvez obtenir une instance de la classe Resources
via context
.
Cela signifie que vous pouvez appeler context.resources.getString()
et transmettre un ID de ressource de chaîne. La chaîne obtenue peut être définie comme text
de textView
dans le holder
ItemViewHolder
. En résumé, cette ligne de code met à jour le conteneur de vues pour afficher la chaîne d'affirmation.
holder.textView.text = context.resources.getString(item.stringResourceId)
La méthode onBindViewHolder()
terminée doit se présenter comme suit :
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
val item = dataset[position]
holder.textView.text = context.resources.getString(item.stringResourceId)
}
Voici le code d'adaptateur terminé.
ItemAdapter.kt
package com.example.affirmations.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.affirmations.R
import com.example.affirmations.model.Affirmation
/**
* Adapter for the [RecyclerView] in [MainActivity]. Displays [Affirmation] data object.
*/
class ItemAdapter(
private val context: Context,
private val dataset: List<Affirmation>
) : RecyclerView.Adapter<ItemAdapter.ItemViewHolder>() {
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder.
// Each data item is just an Affirmation object.
class ItemViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
val textView: TextView = view.findViewById(R.id.item_title)
}
/**
* Create new views (invoked by the layout manager)
*/
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {
// create a new view
val adapterLayout = LayoutInflater.from(parent.context)
.inflate(R.layout.list_item, parent, false)
return ItemViewHolder(adapterLayout)
}
/**
* Replace the contents of a view (invoked by the layout manager)
*/
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
val item = dataset[position]
holder.textView.text = context.resources.getString(item.stringResourceId)
}
/**
* Return the size of your dataset (invoked by the layout manager)
*/
override fun getItemCount() = dataset.size
}
Maintenant que vous avez implémenté ItemAdapter
, vous devez demander à RecyclerView
d'utiliser cet adaptateur.
Modifier MainActivity pour utiliser une RecyclerView
Pour terminer, vous devez utiliser vos classes Datasource
et ItemAdapter
pour créer et afficher des éléments dans RecyclerView
. Cette opération est effectuée dans MainActivity
.
- Ouvrez
MainActivity.kt
. - Dans
MainActivity,
, accédez à la méthodeonCreate()
. Insérez le nouveau code décrit dans les étapes suivantes après l'appel verssetContentView(R.layout.activity_main).
. - Créez une instance de
Datasource
et appelez la méthodeloadAffirmations()
sur cette instance. Stockez la liste d'affirmations renvoyée dans unval
nommémyDataset
.
val myDataset = Datasource().loadAffirmations()
- Créez une variable nommée
recyclerView
et utilisezfindViewById()
pour trouver une référence àRecyclerView
dans la mise en page.
val recyclerView = findViewById<RecyclerView>(R.id.recycler_view)
- Pour indiquer à
recyclerView
d'utiliser la classeItemAdapter
que vous avez créée, créez une instanceItemAdapter
.ItemAdapter
attend deux paramètres : le contexte (this
) de cette activité et les affirmations dansmyDataset
. - Affectez l'objet
ItemAdapter
à la propriétéadapter
de larecyclerView
.
recyclerView.adapter = ItemAdapter(this, myDataset)
- Étant donné que la taille de mise en page de votre
RecyclerView
est fixe dans la mise en page de l'activité, vous pouvez définir le paramètresetHasFixedSize
deRecyclerView
surtrue
. Ce paramètre ne sert qu'à améliorer les performances. Utilisez ce paramètre si vous savez que les modifications apportées au contenu n'ont pas d'incidence sur la taille de mise en page deRecyclerView
.
recyclerView.setHasFixedSize(true)
- Lorsque vous avez terminé, le code de
MainActivity
doit se présenter comme suit.
MainActivity.kt
package com.example.affirmations
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.RecyclerView
import com.example.affirmations.adapter.ItemAdapter
import com.example.affirmations.data.Datasource
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Initialize data.
val myDataset = Datasource().loadAffirmations()
val recyclerView = findViewById<RecyclerView>(R.id.recycler_view)
recyclerView.adapter = ItemAdapter(this, myDataset)
// Use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
recyclerView.setHasFixedSize(true)
}
}
- Exécutez votre application. Une liste de chaînes d'affirmation doit normalement être affichée à l'écran.
Félicitations ! Vous venez de créer une application qui affiche une liste de données avec RecyclerView
et un adaptateur personnalisé. Prenez le temps d'examiner le code que vous avez créé et de comprendre l'interaction entre les différents éléments.
Cette application contient tous les éléments nécessaires pour afficher vos affirmations, mais elle n'est pas tout à fait prête pour la production. L'interface utilisateur pourrait être améliorée. Dans le prochain atelier de programmation, vous apprendrez à ajouter des images à l'application et à peaufiner l'interface utilisateur.
5. Code de solution
Le code de solution de cet atelier de programmation figure dans le projet et le module ci-dessous. Notez que certains fichiers Kotlin se trouvent dans des packages différents, comme indiqué par l'instruction package
au début du fichier.
res/values/strings.xml
<resources>
<string name="app_name">Affirmations</string>
<string name="affirmation1">I am strong.</string>
<string name="affirmation2">I believe in myself.</string>
<string name="affirmation3">Each day is a new opportunity to grow and be a better version of myself.</string>
<string name="affirmation4">Every challenge in my life is an opportunity to learn from.</string>
<string name="affirmation5">I have so much to be grateful for.</string>
<string name="affirmation6">Good things are always coming into my life.</string>
<string name="affirmation7">New opportunities await me at every turn.</string>
<string name="affirmation8">I have the courage to follow my heart.</string>
<string name="affirmation9">Things will unfold at precisely the right time.</string>
<string name="affirmation10">I will be present in all the moments that this day brings.</string>
</resources>
affirmations/data/Datasource.kt
package com.example.affirmations.data
import com.example.affirmations.R
import com.example.affirmations.model.Affirmation
class Datasource {
fun loadAffirmations(): List<Affirmation> {
return listOf<Affirmation>(
Affirmation(R.string.affirmation1),
Affirmation(R.string.affirmation2),
Affirmation(R.string.affirmation3),
Affirmation(R.string.affirmation4),
Affirmation(R.string.affirmation5),
Affirmation(R.string.affirmation6),
Affirmation(R.string.affirmation7),
Affirmation(R.string.affirmation8),
Affirmation(R.string.affirmation9),
Affirmation(R.string.affirmation10)
)
}
}
affirmations/model/Affirmation.kt
package com.example.affirmations.model
data class Affirmation(val stringResourceId: Int)
affirmations/MainActivty.kt
package com.example.affirmations
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.RecyclerView
import com.example.affirmations.adapter.ItemAdapter
import com.example.affirmations.data.Datasource
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Initialize data.
val myDataset = Datasource().loadAffirmations()
val recyclerView = findViewById<RecyclerView>(R.id.recycler_view)
recyclerView.adapter = ItemAdapter(this, myDataset)
// Use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
recyclerView.setHasFixedSize(true)
}
}
affirmations/adapter/ItemAdapter.kt
package com.example.affirmations.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.affirmations.R
import com.example.affirmations.model.Affirmation
/**
* Adapter for the [RecyclerView] in [MainActivity]. Displays [Affirmation] data object.
*/
class ItemAdapter(
private val context: Context,
private val dataset: List<Affirmation>
) : RecyclerView.Adapter<ItemAdapter.ItemViewHolder>() {
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder.
// Each data item is just an Affirmation object.
class ItemViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
val textView: TextView = view.findViewById(R.id.item_title)
}
/**
* Create new views (invoked by the layout manager)
*/
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {
// create a new view
val adapterLayout = LayoutInflater.from(parent.context)
.inflate(R.layout.list_item, parent, false)
return ItemViewHolder(adapterLayout)
}
/**
* Replace the contents of a view (invoked by the layout manager)
*/
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
val item = dataset[position]
holder.textView.text = context.resources.getString(item.stringResourceId)
}
/**
* Return the size of your dataset (invoked by the layout manager)
*/
override fun getItemCount() = dataset.size
}
src/main/res/layout/activty_main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
app:layoutManager="LinearLayoutManager" />
</FrameLayout>
src/main/res/layout/list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/item_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
6. Résumé
- Le widget
RecyclerView
vous aide à afficher une liste de données. RecyclerView
utilise le schéma d'adaptateur pour adapter et afficher les données.ViewHolder
crée et stocke les vues pourRecyclerView
.RecyclerView
intègre desLayoutManagers
.RecyclerView
délègue la disposition des éléments àLayoutManagers
.
Pour implémenter l'adaptateur :
- Créez une classe pour l'adaptateur ;
ItemAdapter
, par exemple. - Créez une classe
ViewHolder
personnalisée qui représente une seule vue d'élément de liste. Effectuez une extension à partir de la classeRecyclerView.ViewHolder
. - Modifiez la classe
ItemAdapter
pour l'étendre à partir deRecyclerView
.Adapter
avec la classeViewHolder
personnalisée. - Implémentez les méthodes suivantes dans l'adaptateur :
getItemsCount()
,onCreateViewHolder()
etonBindViewHolder()
.