Mises en page adaptatives

1. Avant de commencer

Les appareils Android sont disponibles dans un large éventail de formes, de tailles et de facteurs de forme. Vous devez concevoir votre application pour qu'elle s'exécute sur ces différents types d'appareils, quelle que soit la taille de l'écran. Il se peut que les développeurs qui créent des applications prêtes pour la production acceptent Android Wear, Android Auto et Android TV. Cependant, ces sujets ne sont pas abordés dans ce cours. Lorsque votre application est compatible avec la plus grande variété d'écrans possible, vous pouvez la rendre accessible à un maximum d'utilisateurs sur différents appareils.

Votre application doit présenter une mise en page flexible. Au lieu de définir une mise en page avec des dimensions rigides qui nécessitent un format et une taille d'écran donnés, vous devez faire en sorte qu'elle s'adapte facilement à différentes orientations et tailles d'écran. Le même principe s'applique lorsque votre application s'exécute sur un appareil pliable, dont la taille d'écran et le format peuvent changer en cours d'exécution. À la fin de cet atelier de programmation, nous vous proposerons une brève présentation des appareils pliables.

aecb59fc49fb4abf.png

Conditions préalables

  • Vous êtes capable de télécharger du code dans Android Studio et de l'exécuter.
  • Vous maîtrisez les composants d'architecture Android ViewModel et LiveData.
  • Vous avez une connaissance de base des composants de navigation.

Points abordés

  • Comment ajouter SlidingPaneLayout à votre application.

Objectifs de l'atelier

  • Mettre à jour l'application "Sports" pour l'adapter aux écrans de grande taille.

Ce dont vous avez besoin

  • Un ordinateur sur lequel est installé Android Studio
  • Le code de démarrage de l'application Sports

Télécharger le code de démarrage pour cet atelier de programmation

Cet atelier de programmation fournit un code de démarrage que vous pouvez étendre avec les fonctionnalités qui y sont enseignées. Le code de démarrage peut contenir du code que vous avez déjà vu dans les ateliers de programmation précédents, ainsi que du code inconnu qui sera présenté dans les ateliers suivants.

Pour télécharger le code de cet atelier de programmation à partir de GitHub et l'ouvrir dans Android Studio, procédez comme suit :

  1. Lancez Android Studio.
  2. Dans la fenêtre Bienvenue dans Android Studio, cliquez sur Obtenir à partir de VCS.

61c42d01719e5b6d.png

  1. Dans la boîte de dialogue Obtenir à partir du contrôle des versions, assurez-vous que Git est sélectionné pour Contrôle des versions.

9284cfbe17219bbb.png

  1. Collez l'URL du code fourni dans le champ URL.
  2. Vous pouvez également indiquer une valeur autre que la suggestion par défaut dans le champ Répertoire.

5ddca7dd0d914255.png

  1. Cliquez sur Clone (Cloner). Android Studio commence à récupérer votre code.
  2. Attendez qu'Android Studio s'ouvre.
  3. Sélectionnez le module approprié pour le code de solution, d'application ou de démarrage de votre atelier de programmation.

2919fe3e0c79d762.png

  1. Cliquez sur le bouton Run (Exécuter) 8de56cba7583251f.png pour créer et exécuter votre code.

2. Regarder la vidéo du code pas à pas (facultatif)

Si vous souhaitez voir un formateur réaliser cet atelier de programmation, regardez la vidéo ci-dessous.

Nous vous recommandons d'afficher la vidéo en plein écran (à l'aide de l'icône Ce symbole, qui représente quatre coins dessinés sur un carré noir, correspond au mode plein écran. dans l'angle inférieur droit de la vidéo) pour mieux voir Android Studio et le code.

Cette étape est facultative. Vous pouvez également ignorer la vidéo et passer immédiatement aux instructions de l'atelier de programmation.

3. Présentation de l'application de démarrage

L'application "Sports" se compose de deux écrans. Le premier affiche la liste des sports. L'utilisateur peut sélectionner un sport en particulier. Le deuxième écran s'affiche alors. Il s'agit d'un écran d'informations qui affiche les actualités des sports sélectionnés. Cet écran d'informations affiche un texte d'espace réservé pour simplifier l'implémentation.

Explication du code de démarrage

Les mises en page de l'écran de liste et de l'écran d'informations sont prédéfinies dans le code de démarrage que vous avez téléchargé. Dans ce parcours, vous allez vous concentrer uniquement sur l'adaptation de votre application aux écrans de grande taille. Vous utiliserez SlidingPaneLayout pour tirer parti du grand écran. Voici une présentation rapide de certains fichiers pour vous aider à commencer.

fragment_sports_list.xml

  • Ouvrez res/layout/fragment_sports_list.xml dans la vue Conception.
  • Ce fichier contient la mise en page du premier écran de votre application qui correspond à la liste des sports.
  • Cette mise en page comprend une Recyclerview qui affiche une liste d'actualités sportives.

f50d3e7b41fcb338.png

d9af155f87ddbcdf.png

sports_list_item.xml

  • Ouvrez res/layout/sports_list_item.xml dans la vue Conception.
  • Ce fichier contient la mise en page de chaque élément de Recyclerview.
  • Cette mise en page comprend une vignette du sport, le titre Actualités et un texte d'espace réservé pour des actualités sportives en bref.

b19fd0e779c1d7c3.png

fragment_sports_news.xml

  • Ouvrez res/layout/fragment_sports_news.xml dans la vue Conception.
  • Ce fichier contient la mise en page du deuxième écran de votre application. Cet écran s'affiche lorsque l'utilisateur sélectionne un sport dans Recyclerview.
  • Cette mise en page se compose d'une bannière d'image de sport et d'un texte d'espace réservé pour les actualités sportives.

c2073b1752342d97.png

main_activity.xml et content_main.xml

Ces deux fichiers définissent la disposition d'activité principale avec un seul fragment.

Le graphique de navigation contient deux destinations, l'une pour les listes des sports et l'autre pour les actualités sportives.

dossier res/values

Vous connaissez les fichiers de ressources de ce dossier.

  • colors.xml contient les couleurs du thème utilisées dans l'application.
  • strings.xml contient toutes les chaînes dont votre application a besoin.
  • themes.xml contient la personnalisation de l'interface utilisateur effectuée pour votre application.

MainActivity.kt

Ce fichier contient le code par défaut généré par le modèle pour définir la vue de contenu de l'activité en tant que main_activity.xml. La méthode onSupportNavigateUp() est ignorée afin de gérer la navigation vers le haut par défaut depuis la barre d'application.

model/Sport.kt

Il s'agit d'une classe de données qui contient les données à afficher dans chaque ligne de la Recyclerview de la liste des sports.

data/SportsData.kt

Ce fichier contient une fonction appelée getSportsData() qui renvoie un ArrayList prérempli avec des données sportives codées en dur.

SportsViewModel.kt

Il s'agit du ViewModel partagé pour l'application. ViewModel est partagé par SportsListFragment, le premier écran avec la liste des sports, et NewsDetailsFragment, le deuxième écran avec les actualités sportives détaillées.

  • La propriété _currentSport est de type MutableLiveData,, qui stocke le sport sélectionné par l'utilisateur. La propriété currentSport est la propriété de support pour _currentSport. Elle est exposée en tant que version publique en lecture seule pour les autres classes.
  • La propriété _sportsData contient la liste des données sportives. sportsData est semblable à la propriété précédente. Il s'agit de la version publique en lecture seule de cette propriété.
  • Le bloc d'initialisation init{} initialise _currentSport et _sportsData. _sportsData est initialisé avec la liste complète des sports provenant de data/SportsData.kt. _currentSport est initialisé avec le premier élément de la liste.
  • La fonction updateCurrentSport() utilise une instance Sports et met à jour _currentSport avec la valeur transmise.

SportsAdapter.kt

Il s'agit de l'adaptateur pour RecyclerView. Dans le constructeur, l'écouteur de clics est transmis. Le code de ce fichier est, en grande partie, un code récurrent que vous avez découvert lors d'ateliers de programmation précédents.

SportsListFragment.kt

Il s'agit du premier fragment d'écran où est affichée la liste des sports.

  • La fonction onCreateView() gonfle le code XML de mise en page fragment_sports_list à l'aide de l'objet de liaison.
  • La fonction onViewCreated() configure l'adaptateur RecyclerView. Elle met à jour le sport sélectionné par l'utilisateur comme étant le sport actuel dans le ViewModel partagé, SportsViewModel. Elle permet d'accéder à l'écran d'informations contenant les actualités sportives et envoie la liste des sports à l'adaptateur pour l'afficher à l'aide de submitList(List).

NewsDetailsFragment.kt

Il s'agit du deuxième écran de votre application, où est affiché un texte d'espace réservé pour les actualités sportives.

  • La fonction onCreateView() gonfle le code XML de mise en page fragment_sports_news à l'aide de l'objet de liaison.
  • La fonction onViewCreated() associe un observateur à la propriété de SportsViewModel, currentSport, pour mettre à jour automatiquement l'interface utilisateur lorsque les données changent. Le titre, l'image et les actualités du sport sont mis à jour dans l'observateur.

Créer et exécuter l'application

  1. Créez et exécutez l'application sur un émulateur ou un appareil. Sélectionnez n'importe quel élément de la liste des sports. L'application devrait alors accéder au deuxième écran avec un texte d'espace réservé pour les actualités.

4. Schéma List-Detail

L'application de démarrage actuelle n'exploite pas tout l'espace d'affichage sur les appareils plus grands tels que les tablettes. Pour résoudre ce problème, vous allez afficher l'interface utilisateur de l'application à l'aide du schéma List-Detail, que vous découvrirez dans cet atelier de programmation.

Exécuter l'application sur une tablette

Dans cette tâche, vous allez créer un émulateur avec un profil pour tablette. Une fois l'émulateur créé, vous allez exécuter le code de démarrage de l'application "Sports" et observer l'interface utilisateur.

  1. Dans Android Studio, accédez à Outils > AVD Manager.
  2. La fenêtre Gestionnaire des appareils virtuels Android s'affiche. Cliquez sur + Créer un appareil virtuel… en bas de l'écran.
  3. La fenêtre Configuration de l'appareil virtuel s'affiche. Vous allez maintenant configurer le matériel et l'OS de l'émulateur. Cliquez sur Tablette dans le volet gauche. Sélectionnez Pixel C ou tout autre profil matériel similaire dans le volet central.

8303f9b3e70321eb.png

  1. Appuyez sur Suivant.
  2. Sélectionnez la dernière image système. Au moment de la rédaction de cet atelier de programmation, la dernière version était R (niveau d'API 30).
  3. Appuyez sur Suivant.
  4. Vous pouvez renommer l'appareil virtuel maintenant (cette étape est facultative).
  5. Cliquez sur Terminer.
  6. Vous revenez alors à la fenêtre Gestionnaire des appareils virtuels Android. Cliquez sur l'icône de lancement 38752506de85d293.png à côté du nouvel appareil virtuel.
  7. L'émulateur doté du profil pour tablette doit normalement se lancer. Veuillez patienter, cette opération peut prendre un certain temps.
  8. Fermez la fenêtre Gestionnaire des appareils virtuels Android.
  9. Exécutez l'application "Sports" sur le nouvel émulateur.

200e209de7a2f0ad.png

Notez que sur les appareils de grande taille, l'application n'utilise pas tout l'écran. Le schéma list-detail est plus efficace sur un grand écran qu'une liste. Un schéma item-detail (également appelé schéma master-detail) affiche une liste d'éléments sur un côté de la mise en page. Les détails s'affichent à côté lorsque vous appuyez sur un élément. En général, ces vues ne s'affichent que sur les grands écrans (des tablettes, par exemple), car elles offrent davantage d'espace pour le contenu.

Les images suivantes illustrent un exemple de schéma list-detail :

71698910dd129a91.png

Les schémas list-detail ci-dessus affichent une liste d'éléments à gauche et des informations sur l'élément sélectionné à droite.

De la même manière, si vous utilisez le schéma ci-dessus dans votre application "Sports", le fragment d'actualités correspondra à l'écran d'informations.

51c9542717d2f875.png

Dans cet atelier de programmation, vous allez apprendre à implémenter l'interface utilisateur de list-detail à l'aide de SlidingPaneLayout.

5. Schéma SlidingPaneLayout

Il se peut que l'interface utilisateur de list-detail doive se comporter différemment en fonction de la taille de l'écran. Sur les grands écrans, il y a suffisamment d'espace pour afficher les volets de liste et de détails côte à côte. Cliquez sur un élément de la liste pour afficher les informations correspondantes dans le volet de détails. Cependant, sur les petits écrans, on a l'impression qu'il n'y a pas suffisamment d'espace. Au lieu d'afficher les deux volets en même temps, il est préférable de les afficher un par un. Au départ, le volet de liste remplit tout l'écran. Appuyez sur un élément pour remplacer le volet de liste par le volet de détails, qui occupe également tout l'écran.

Vous allez apprendre à utiliser un modèle SlidingPaneLayout pour gérer la logique permettant de sélectionner l'expérience utilisateur appropriée en fonction de la taille d'écran actuelle.

b0a205de3494e95d.gif

Comme vous pouvez le voir, le volet de détails glisse par-dessus le volet de liste sur les petits écrans.

Les images ci-dessous montrent comment SlidingPaneLayout apparaît sur un écran plus petit. Lorsqu'un élément de la liste est sélectionné, vous pouvez constater que le volet de détails chevauche le volet de liste. Les deux volets sont donc toujours présents.

e26f94d9579b6121.png

471b0b38d4dfa95a.png

Par conséquent, SlidingPaneLayout permet d'afficher deux volets côte à côte sur les appareils plus grands, tout en s'adaptant automatiquement pour n'afficher qu'un seul volet à la fois sur les appareils plus petits tels que les téléphones.

6. Ajouter des dépendances de bibliothèque

  1. Ouvrez build.gradle (Module: Sports.app).
  2. Dans la section dependencies, incluez la dépendance suivante pour utiliser SlidingPaneLayout dans votre application.
dependencies {
...
    implementation "androidx.slidingpanelayout:slidingpanelayout:1.2.0-beta01"
}

7. Configurer le fichier XML du fragment de liste des sports

Dans cette tâche, vous allez convertir la mise en page racine de fragment_sports_list en SlidingPaneLayout. Comme vous l'avez déjà vu précédemment, SlidingPaneLayout fournit une mise en page horizontale à deux volets à utiliser au niveau supérieur d'une interface utilisateur. Cette mise en page utilise le premier volet en tant que liste de contenu ou navigateur. Elle dépend d'une vue détaillée principale pour afficher du contenu dans l'autre volet.

Dans l'application "Sports", le premier volet correspond à la RecyclerView qui affiche la liste des sports, tandis que le deuxième volet affiche les actualités sportives.

Ajouter SlidingPaneLayout

  1. Ouvrez fragment_sports_list.xml. Notez que la mise en page racine est un FrameLayout.
  2. Remplacez FrameLayout par androidx.slidingpanelayout.widget.SlidingPaneLayout.
<androidx.slidingpanelayout.widget.SlidingPaneLayout
   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=".SportsListFragment">

   <androidx.recyclerview.widget.RecyclerView...>
</androidx.slidingpanelayout.widget.SlidingPaneLayout>
  1. Ajoutez un attribut android:id à SlidingPaneLayout et attribuez-lui la valeur @+id/sliding_pane_layout.
<androidx.slidingpanelayout.widget.SlidingPaneLayout
   ...
   android:id="@+id/sliding_pane_layout"
   ...>

Ajouter un deuxième volet à SlidingPaneLayout

Dans cette tâche, vous allez ajouter un deuxième élément enfant à SlidingPaneLayout. Il sera affiché en tant que volet de contenu de droite.

  1. Dans fragment_sports_list.xml, sous RecyclerView, ajoutez un deuxième élément enfant, androidx.fragment.app.FragmentContainerView.
  2. Ajoutez les attributs obligatoires, layout_height et layout_width, à FragmentContainerView. Attribuez-leur la valeur match_parent. Notez que vous mettrez à jour ces valeurs ultérieurement.
<androidx.fragment.app.FragmentContainerView
   android:layout_height="match_parent"
   android:layout_width="match_parent"/>
  1. Ajoutez un attribut android:id à FragmentContainerView et attribuez-lui la valeur @+id/detail_container.
android:id="@+id/detail_container"
  1. Ajoutez NewsDetailsFragment à FragmentContainerView en utilisant l'attribut android:name.
android:name="com.example.android.sports.NewsDetailsFragment"

Mettre à jour l'attribut layout_width

SlidingPaneLayout utilise la largeur des deux volets pour déterminer s'ils doivent être affichés côte à côte. Par exemple, si le volet de liste doit avoir une taille minimale de 300dp et que le volet de détails a besoin de 400dp, SlidingPaneLayout affiche automatiquement les deux volets côte à côte, à condition que sa largeur disponible soit d'au moins 700dp.

Les vues enfants se chevauchent si leur largeur combinée dépasse la largeur disponible dans SlidingPaneLayout. Dans ce cas, les vues enfants sont agrandies pour remplir la largeur disponible dans SlidingPaneLayout.

Pour déterminer la largeur des vues enfants, vous devez disposer d'informations de base sur la largeur d'écran des appareils. Le tableau suivant présente la liste de points d'arrêt permettant de concevoir, développer et tester des mises en page d'application redimensionnables. Ils ont été choisis spécialement pour trouver le juste équilibre entre la simplicité de mise en page et la souplesse d'optimisation de l'application en fonction de cas spécifiques.

Largeur

Point d'arrêt

Représentation de l'appareil

Largeur compacte

< 600 dp

99,96 % des téléphones en mode portrait

Largeur moyenne

Plus de 600 dp

93,73 % des tablettes en mode portrait. Grands écrans internes dépliés en mode portrait.

Grande largeur

Plus de 840 dp

97,22 % des tablettes en mode paysage. Grands écrans internes déployés en mode paysage.

a247a843310d061a.png

Dans l'application Sports, vous souhaitez afficher un seul volet, la liste des sports sur les téléphones, c'est-à-dire sur les appareils dont la largeur est inférieure à 600dp. Pour afficher les deux volets sur des tablettes, la largeur combinée doit être supérieure à 840dp. Vous pouvez utiliser une largeur de 550dp pour le premier élément enfant, la vue recycleur, et une largeur de 300dp pour le deuxième élément enfant, le FragmentContainerView.

  1. Dans fragment_sports_list.xml, définissez la largeur de mise en page de RecyclerView sur 550dp et celle de FragmentContainerView sur 300dp.
<androidx.recyclerview.widget.RecyclerView
   ...
   android:layout_width="550dp"
   .../>

<androidx.fragment.app.FragmentContainerView
   ...
   android:layout_width="300dp"
   .../>
  1. Exécutez l'application sur un émulateur avec le profil de tablette et un émulateur avec le profil de téléphone.

ad148a96d7487e66.png

Notez que deux volets sont affichés sur la tablette. Vous corrigerez la largeur du deuxième volet de la tablette à l'étape suivante.

  1. Exécutez l'application sur l'émulateur avec le profil de téléphone.

a6be6d199d2975ac.png

Ajouter layout_weight

Dans cette tâche, vous allez corriger l'interface utilisateur sur la tablette et faire en sorte que le deuxième volet occupe tout l'espace restant.

SlidingPaneLayout permet de définir la façon dont l'espace restant est divisé après la mesure à l'aide du paramètre de mise en page layout_weight sur les vues enfants si celles-ci ne se chevauchent pas. Ce paramètre s'applique uniquement à la largeur.

  1. Dans fragment_sports_list.xml, ajoutez layout_weight à FragmentContainerView et attribuez-lui la valeur 1. Le deuxième volet est agrandi pour occuper l'espace restant après la mesure du volet de liste.
android:layout_weight="1"
  1. Exécutez l'application.

ce3a93fe501ee5dc.png

Félicitations ! Vous avez ajouté SlidingPaneLayout. Cependant, vous n'avez pas encore terminé. Vous devez encore implémenter la navigation vers l'arrière et mettre à jour le deuxième volet lorsqu'un élément est sélectionné dans la liste. Vous effectuerez ces opérations lors d'une tâche ultérieure.

8. Remplacer le volet de vue détaillée

Exécutez l'application sur l'émulateur avec le profil de tablette. Sélectionnez un élément dans la liste "Sports". Notez que l'application accède au volet de détails.

8fedee8d4837909.png

Dans cette tâche, vous allez résoudre ce problème. Le contenu du double volet est en cours de mise à jour avec le sport sélectionné. L'application accède ensuite à NewsDetailsFragment.

  1. Dans le fichier SportsListFragment, dans la fonction onViewCreated(), recherchez les lignes suivantes qui permettent d'accéder à l'écran d'informations.
// Navigate to the details screen
val action = SportsListFragmentDirections.actionSportsListFragmentToNewsFragment()
this.findNavController().navigate(action)
  1. Remplacez les lignes ci-dessus par le code suivant :
binding.slidingPaneLayout.openPane()

Appelez openPane() sur SlidingPaneLayout pour permuter les deux volets. Cela n'aura aucun effet visible si les deux volets sont affichés, comme c'est le cas sur une tablette.

  1. Exécutez l'application sur l'émulateur de tablette et de téléphone. Notez que le contenu du double volet est mis à jour correctement.

b0d3c8c263be15f8.png

Votre prochaine tâche consistera à enrichir l'application d'une fonctionnalité de navigation vers l'arrière personnalisée.

9. Ajouter la navigation vers l'arrière personnalisée

Pour les appareils de plus petite taille sur lesquels les volets de liste et de détails se chevauchent, assurez-vous que le bouton "Retour" du système fait revenir l'utilisateur du volet de détails au volet de liste. Pour ce faire, fournissez une navigation vers l'arrière personnalisée et connectez un OnBackPressedCallback à l'état actuel de SlidingPaneLayout.

Navigation vers l'arrière

La navigation vers l'arrière permet aux utilisateurs de revenir en arrière dans l'historique des écrans qu'ils ont déjà consultés. Tous les appareils Android proposent un bouton "Retour" pour ce type de navigation. En fonction de l'appareil Android de l'utilisateur, il peut s'agir d'un bouton physique ou d'un bouton logiciel.

Navigation vers l'arrière personnalisée

Android conserve une pile "Retour" des destinations à mesure que l'utilisateur parcourt l'application. Cela permet généralement à Android de revenir correctement aux destinations précédentes lorsque l'utilisateur appuie sur le bouton "Retour". Toutefois, dans certains cas, il se peut que votre application doive implémenter son propre comportement "Retour" afin d'offrir la meilleure expérience utilisateur possible.

Par exemple, lors de l'utilisation d'une WebView telle qu'un navigateur Chrome, vous pouvez ignorer le comportement par défaut du bouton Retour pour permettre à l'utilisateur de revenir en arrière dans son historique de navigation Web au lieu des écrans précédents de votre application.

De même, vous devez fournir une navigation vers l'arrière personnalisée vers SlidingPaneLayout et parcourir l'application à partir du volet de détails jusqu'au volet de liste.

Implémenter la navigation vers l'arrière personnalisée

Pour implémenter la navigation vers l'arrière personnalisée dans votre application "Sports", vous devez :

  • Définir un rappel personnalisé pour gérer l'utilisation de la touche Retour, ce qui remplace OnBackPressedCallback.
  • Enregistrer et ajouter l'instance de rappel.

Commencez par définir le rappel personnalisé.

  1. Dans le fichier SportsListFragment, ajoutez une classe sous la définition de classe SportsListFragment. Nommez-la SportsListOnBackPressedCallback.
  2. Transmettez une instance private de SlidingPaneLayout en tant que paramètre constructeur.
class SportsListOnBackPressedCallback(
   private val slidingPaneLayout: SlidingPaneLayout
)
  1. Étendez la classe depuis OnBackPressedCallback. La classe OnBackPressedCallback gère les rappels onBackPressed. Vous allez bientôt corriger l'erreur liée au paramètre constructeur.
class SportsListOnBackPressedCallback(
   private val slidingPaneLayout: SlidingPaneLayout
): OnBackPressedCallback()

Le constructeur de OnBackPressedCallback utilise une valeur booléenne pour l'état initial activé. C'est seulement quand un rappel est activé (isEnabled() renvoie la valeur "true") que le dispatcher appelle la méthode handleOnBackPressed() du rappel pour gérer l'événement du bouton "Retour".

  1. Transmettez slidingPaneLayout.isSlideable* && slidingPaneLayout.isOpen* en tant que paramètre constructeur à OnBackPressedCallback. La valeur booléenne isSlideable n'est définie sur "true" que s'il est possible de faire glisser le deuxième volet, c'est-à-dire sur un écran de plus petite taille où un seul volet est affiché. La valeur de isOpen sera true si le deuxième volet (le volet de contenu) est entièrement ouvert.
class SportsListOnBackPressedCallback(
   private val slidingPaneLayout: SlidingPaneLayout
): OnBackPressedCallback(slidingPaneLayout.isSlideable && slidingPaneLayout.isOpen)

Ce code garantit que le rappel n'est activé que sur les appareils dotés d'un écran de petite taille et lorsque le volet de contenu est ouvert.

  1. Pour corriger l'erreur concernant la méthode non implémentée, cliquez sur l'ampoule rouge 5fdf362480bfe665.png, puis sélectionnez Implémenter les membres.
  2. Cliquez sur OK dans la fenêtre pop-up Implémenter les membres pour ignorer la méthode handleOnBackPressed.

Votre classe doit se présenter comme suit :

class SportsListOnBackPressedCallback(
   private val slidingPaneLayout: SlidingPaneLayout
): OnBackPressedCallback(slidingPaneLayout.isSlideable && slidingPaneLayout.isOpen) {
   /**
    * Callback for handling the [OnBackPressedDispatcher.onBackPressed] event.
    */
   override fun handleOnBackPressed() {
       TODO("Not yet implemented")
   }
}
  1. Dans la fonction handleOnBackPressed(), supprimez l'instruction TODO, puis ajoutez le code suivant pour fermer le volet de contenu et revenir au volet de liste.
slidingPaneLayout.closePane()

Surveiller les événements de SlidingPaneLayout

En plus de gérer les événements de navigation vers l'arrière, vous devez écouter et surveiller les événements liés au volet coulissant. Lorsque l'utilisateur fait glisser le volet de contenu, le rappel doit être activé ou désactivé en conséquence. Pour ce faire, utilisez PanelSlideListener.

L'interface SlidingPaneLayout.PanelSlideListener contient trois méthodes abstraites : onPanelSlide(), onPanelOpened() et onPanelClosed(). Ces méthodes sont appelées lorsque l'utilisateur fait glisser, ouvre et ferme le volet de détails.

  1. Étendez la classe SportsListOnBackPressedCallback depuis SlidingPaneLayout.PanelSlideListener.
  2. Pour résoudre l'erreur, implémentez les trois méthodes. Cliquez sur l'ampoule rouge, puis sélectionnez Implémenter les membres dans Android Studio.

ad52135eecbee09f.png

  1. Votre classe SportsListOnBackPressedCallback doit se présenter comme suit :
class SportsListOnBackPressedCallback(
   private val slidingPaneLayout: SlidingPaneLayout
): OnBackPressedCallback(slidingPaneLayout.isSlideable && slidingPaneLayout.isOpen),
  SlidingPaneLayout.PanelSlideListener{

   override fun handleOnBackPressed() {
       slidingPaneLayout.closePane()
   }

   override fun onPanelSlide(panel: View, slideOffset: Float) {
       TODO("Not yet implemented")
   }

   override fun onPanelOpened(panel: View) {
       TODO("Not yet implemented")
   }

   override fun onPanelClosed(panel: View) {
       TODO("Not yet implemented")
   }
}
  1. Supprimez les instructions TODO.
  2. Activez le rappel OnBackPressedCallback lorsque le volet de détails est ouvert (c'est-à-dire lorsqu'il est visible). Pour ce faire, vous pouvez appeler la fonction setEnabled() et transmettre true. Écrivez le code suivant dans onPanelOpened() :
setEnabled(true)
  1. Le code ci-dessus peut être simplifié à l'aide de la syntaxe d'accès aux propriétés.
override fun onPanelOpened(panel: View) {
   isEnabled = true
}
  1. De même, définissez isEnabled sur false, lorsque le volet de détails est fermé.
override fun onPanelClosed(panel: View) {
   isEnabled = false
}
  1. La dernière étape d'exécution du rappel consiste à ajouter la classe d'écouteur SportsListOnBackPressedCallback à la liste des écouteurs qui sont informés lorsque l'utilisateur fait glisser le volet de détails. Ajoutez un bloc init à la classe SportsListOnBackPressedCallback. Dans le bloc init, appelez slidingPaneLayout.addPanelSlideListener() en transmettant this.
init {
   slidingPaneLayout.addPanelSlideListener(this)
}

La classe SportsListOnBackPressedCallback terminée doit se présenter comme suit :

class SportsListOnBackPressedCallback(
   private val slidingPaneLayout: SlidingPaneLayout
): OnBackPressedCallback(slidingPaneLayout.isSlideable && slidingPaneLayout.isOpen),
  SlidingPaneLayout.PanelSlideListener{

   init {
       slidingPaneLayout.addPanelSlideListener(this)
   }

   override fun handleOnBackPressed() {
       slidingPaneLayout.closePane()
   }

   override fun onPanelSlide(panel: View, slideOffset: Float) {
   }

   override fun onPanelOpened(panel: View) {
       isEnabled = true
   }

   override fun onPanelClosed(panel: View) {
       isEnabled = false
   }
}

Enregistrer le rappel

Pour voir votre rappel en action, enregistrez-le à l'aide du dispatcher, OnBackPressedDispatcher.

La classe de base de FragmentActivity vous permet de contrôler le comportement du bouton "Retour" en utilisant son OnBackPressedDispatcher. OnBackPressedDispatcher contrôle la façon dont les événements du bouton "Retour" sont envoyés à un ou plusieurs objets OnBackPressedCallback.

Ajoutez le rappel à l'aide de la méthode addCallback(). Cette méthode utilise un objet LifecycleOwner. Cela vous aide à assurer que OnBackPressedCallback n'est ajouté que lorsque LifecycleOwner est défini sur Lifecycle.State.STARTED. L'activité ou le fragment supprime également les rappels enregistrés lorsque le LifecycleOwner associé est détruit. Cela permet d'éviter les fuites de mémoire et de faire en sorte qu'il puisse être utilisé dans des fragments ou d'autres propriétaires de cycle de vie ayant une durée de vie plus courte.

La méthode addCallback() utilise également l'instance de classe de rappel en tant que deuxième paramètre. Pour enregistrer le rappel, procédez comme suit :

  1. Dans le fichier SportsListFragment, dans la fonction onViewCreated(), en dessous de la déclaration de la variable de liaison, créez une instance pour SlidingPaneLayout et attribuez-lui la valeur binding.slidingPaneLayout.
val slidingPaneLayout = binding.slidingPaneLayout
  1. Dans le fichier SportsListFragment, dans la fonction onViewCreated(), en dessous de la déclaration de slidingPaneLayout, ajoutez le code suivant :
// Connect the SlidingPaneLayout to the system back button.
requireActivity().onBackPressedDispatcher.addCallback(
   viewLifecycleOwner,
   SportsListOnBackPressedCallback(slidingPaneLayout)
)

Le code ci-dessus utilise addCallback(), en transmettant viewLifecycleOwner et une instance de SportsListOnBackPressedCallback. Ce rappel n'est actif que pendant le cycle de vie du fragment.

  1. Il est maintenant temps d'exécuter l'application sur un émulateur avec un profil de téléphone et de voir comment fonctionne le bouton "Retour" personnalisé.

33967fa8fde5b902.gif

10. Mode verrouillé

Lorsque les volets de liste et de détails se chevauchent sur des écrans plus petits, comme des téléphones, les utilisateurs peuvent, par défaut, balayer l'écran dans les deux sens et basculer librement entre les deux volets, même s'ils n'utilisent pas la navigation par gestes. Vous pouvez verrouiller ou déverrouiller le volet de détails en définissant le mode verrouillé de SlidingPaneLayout.

  1. Dans l'émulateur avec le profil de téléphone, balayez le volet de détails pour le faire sortir de l'écran.
  2. Vous pouvez également balayer le volet Détails pour qu'il s'affiche à l'écran. Essayez par vous-même.
  3. Cette fonctionnalité n'est pas souhaitable dans votre application Sports. Il est recommandé de verrouiller SlidingPaneLayout pour empêcher tout mouvement de balayage à l'aide de gestes. Pour implémenter cela, dans la méthode onViewCreated(), sous la définition slidingPaneLayout, définissez lockMode sur LOCK_MODE_LOCKED :
slidingPaneLayout.lockMode = SlidingPaneLayout.LOCK_MODE_LOCKED

Pour en savoir plus sur les autres modes de verrouillage, veuillez consulter la documentation.

  1. Exécutez à nouveau l'application. Comme vous pouvez le constater, le volet de détails est maintenant verrouillé.

Félicitations ! Vous avez ajouté SlidingPaneLayout à votre application.

11. Code de solution

Le code de solution de cet atelier de programmation figure dans le projet et le module ci-dessous.

  1. Accédez à la page du dépôt GitHub fournie pour le projet.
  2. Vérifiez que le nom de la branche correspond à celui spécifié dans l'atelier de programmation. Par exemple, dans la capture d'écran suivante, le nom de la branche est main.

1e4c0d2c081a8fd2.png

  1. Sur la page GitHub du projet, cliquez sur le bouton Code pour afficher une fenêtre pop-up.

1debcf330fd04c7b.png

  1. Dans la fenêtre pop-up, cliquez sur le bouton Download ZIP (Télécharger le fichier ZIP) pour enregistrer le projet sur votre ordinateur. Attendez la fin du téléchargement.
  2. Recherchez le fichier sur votre ordinateur (il se trouve probablement dans le dossier Téléchargements).
  3. Double-cliquez sur le fichier ZIP pour le décompresser. Un dossier contenant les fichiers du projet est alors créé.

Ouvrir le projet dans Android Studio

  1. Lancez Android Studio.
  2. Dans la fenêtre Welcome to Android Studio (Bienvenue dans Android Studio), cliquez sur Open (Ouvrir).

d8e9dbdeafe9038a.png

Remarque : Si Android Studio est déjà ouvert, sélectionnez l'option de menu File > Open (Fichier > Ouvrir).

8d1fda7396afe8e5.png

  1. Dans l'explorateur de fichiers, accédez à l'emplacement du dossier du projet décompressé (il se trouve probablement dans le dossier Téléchargements).
  2. Double-cliquez sur le dossier de ce projet.
  3. Attendez qu'Android Studio ouvre le projet.
  4. Cliquez sur le bouton Run (Exécuter) 8de56cba7583251f.png pour créer et exécuter l'application. Assurez-vous qu'elle fonctionne correctement.

12. En savoir plus