1. Introduction
Dans cet atelier de programmation, vous allez apprendre à créer des applications adaptatives pour les téléphones, les tablettes et les pliables, et à améliorer la maniabilité avec Jetpack Compose. Vous découvrirez également les bonnes pratiques concernant l'utilisation des composants et de la thématisation Material 3.
Avant d'entrer dans le vif du sujet, il est important de comprendre ce que nous entendons par "adaptabilité".
Adaptabilité
L'UI de votre application doit être responsive aux différentes tailles de fenêtre, orientations et facteurs de forme. La mise en page adaptative change en fonction de l'espace disponible à l'écran. Ces modifications vont d'un simple ajustement de la mise en page pour remplir l'espace, en choisissant des styles de navigation adaptés, à un changement complet de la mise en page afin d'utiliser l'espace supplémentaire.
Pour en savoir plus, consultez la section Design adaptatif.
Dans cet atelier de programmation, vous allez apprendre à utiliser Jetpack Compose et réfléchir à son adaptabilité. Vous allez créer une application (appelée Reply) pour savoir comment implémenter l'adaptabilité sur tous les types d'écrans. Vous découvrirez comment la maniabilité et la maniabilité fonctionnent ensemble pour offrir une expérience utilisateur optimale.
Points abordés
- Concevoir votre application pour cibler toutes les tailles de fenêtre avec Jetpack Compose.
- Cibler votre application pour différents pliables.
- Utiliser différents types de navigation pour améliorer la maniabilité et l'accessibilité.
- Utiliser les composants Material 3 pour offrir une expérience optimale en fonction de la taille de fenêtre
Prérequis
- La dernière version stable d'Android Studio
- Appareil virtuel redimensionnable Android 13.
- Connaissances de Kotlin.
- Connaissances de base de Compose (annotation
@Composable, entre autres). - Connaissances de base sur les mises en page Compose (
RowetColumn, par exemple). - Connaissances de base sur les modificateurs (par exemple,
Modifier.padding()).
Pour cet atelier de programmation, vous utiliserez l'émulateur redimensionnable, qui vous permet de basculer entre différents types d'appareils et tailles de fenêtre.

Si vous ne connaissez pas Compose, il peut être utile de suivre l'atelier de programmation Principes de base de Jetpack Compose avant de poursuivre.
Ce que vous allez faire
- Une application de client de messagerie interactive appelée Reply, qui utilise les bonnes pratiques pour garantir des conceptions adaptables, différentes navigations Material et une utilisation optimale de l'espace à l'écran.

2. Configuration
Pour obtenir le code de cet atelier de programmation, clonez le dépôt GitHub à partir de la ligne de commande :
git clone https://github.com/android/codelab-android-compose.git cd codelab-android-compose/AdaptiveUiCodelab
Vous pouvez aussi télécharger le dépôt sous la forme d'un fichier ZIP :
Nous vous recommandons de commencer par le code de la branche main, puis de suivre l'atelier étape par étape, à votre propre rythme.
Ouvrir le projet dans Android Studio
- Dans la fenêtre Welcome to Android Studio (Bienvenue dans Android Studio), sélectionnez
Open an existing Project (Ouvrir un projet existant). - Sélectionnez le dossier
<Download Location>/AdaptiveUiCodelab. (assurez-vous de sélectionner le répertoireAdaptiveUiCodelabcontenantbuild.gradle.) - Une fois qu'Android Studio a importé le projet, vérifiez que vous pouvez exécuter la branche
main.
Se familiariser avec le code de démarrage
Le code de la branche main contient le package ui. Vous allez utiliser les fichiers suivants du package :
MainActivity.kt: activité de point d'entrée à partir de laquelle vous démarrez l'application.ReplyApp.kt: contient les composables de l'UI de l'écran principal.ReplyHomeViewModel.kt: fournit les données et l'état de l'UI pour le contenu de l'application.ReplyListContent.kt: contient les composables permettant de fournir des listes et des écrans détaillés.
Si vous exécutez cette application sur un émulateur redimensionnable et que vous essayez différents types d'appareils (tels qu'un téléphone ou une tablette), l'UI épouse l'espace donné plutôt que d'exploiter l'espace de l'écran ou de fournir une ergonomie maniable.


Vous allez le mettre à jour pour optimiser l'espace à l'écran, améliorer la convivialité et l'expérience utilisateur globale.
3. Assurer l'adaptation des applications
Cette section définit l'adaptation des applications et les composants que Material 3 met à votre disposition pour simplifier la tâche. Nous aborderons aussi les types d'écrans et les États que vous allez cibler, y compris les téléphones, les tablettes, les grandes tablettes et les pliables.
Vous commencerez par passer en revue les principes liés aux tailles de fenêtre, aux positions de pliage et aux options de navigation. Vous pouvez ensuite utiliser ces API dans votre application pour la rendre plus adaptative.
Tailles de fenêtre
Les appareils Android se déclinent sous toutes les formes et toutes les tailles, des téléphones aux pliables, en passant par les tablettes et les appareils ChromeOS. Pour accepter un maximum de tailles de fenêtre, votre UI doit être responsive et adaptative. Pour vous aider à déterminer le seuil auquel modifier l'UI de votre application, nous avons défini des valeurs de point d'arrêt. Elles permettent de classer les appareils en classes de tailles prédéfinies (compacte, moyenne et étendue), appelées classes de tailles de fenêtre. Cet ensemble de points d'arrêt de fenêtre d'affichage définis permettent de concevoir, de développer et de tester des mises en page d'applications responsives et adaptatives.
Les catégories ont été spécialement choisies pour équilibrer la simplicité de la mise en page et la flexibilité qui permet d'optimiser votre application dans des cas spécifiques. La classe de taille de fenêtre dépend toujours de l'espace d'écran disponible pour l'application, qui peut ne pas correspondre à l'intégralité de l'écran physique pour le multitâche ou d'autres segmentations.


La largeur et la hauteur disponibles sont évaluées séparément. Votre application peut donc être associée à deux classes de taille de fenêtre : une pour la largeur et une pour la hauteur. La largeur disponible est généralement plus importante que la hauteur disponible en raison de l'omniprésence du défilement vertical. Dans ce cas, vous utilisez également les classes de largeur.
États de pliage
Les appareils pliables présentent encore plus de situations auxquelles votre application peut s'adapter en raison de leurs différentes tailles et de la présence de charnières. Les charnières peuvent masquer une partie de l'écran, ce qui rend cette zone inadaptée à l'affichage de contenu. Elles peuvent également être séparées, ce qui signifie qu'il existe deux écrans physiques distincts lorsque l'appareil est déplié.

De plus, l'utilisateur peut regarder l'écran intérieur lorsque la charnière est partiellement ouverte, ce qui entraîne différentes postures physiques en fonction de l'orientation du pli : la position à plat (pli horizontal, illustré à droite dans l'image ci-dessus) et la position debout (pli vertical).
En savoir plus sur les positions et les charnières de pliage
Tous ces éléments doivent être pris en compte lors de l'implémentation de mises en page adaptatives compatibles avec les appareils pliables.
Obtenir des informations adaptatives
La bibliothèque Material3 adaptive permet d'accéder facilement aux informations sur la fenêtre dans laquelle votre application s'exécute.
- Ajoutez des entrées pour cet artefact et sa version au fichier du catalogue de versions :
gradle/libs.versions.toml
[versions]
material3Adaptive = "1.0.0"
[libraries]
androidx-material3-adaptive = { module = "androidx.compose.material3.adaptive:adaptive", version.ref = "material3Adaptive" }
- Dans le fichier build du module d'application, ajoutez la nouvelle dépendance de bibliothèque, puis effectuez une synchronisation Gradle :
app/build.gradle.kts
dependencies {
implementation(libs.androidx.material3.adaptive)
}
Désormais, dans n'importe quelle portée composable, vous pouvez utiliser currentWindowAdaptiveInfo() pour obtenir un objet WindowAdaptiveInfo contenant des informations telles que la classe de taille de fenêtre actuelle et indiquant si l'appareil est dans une position pliable, comme la position sur table.
Vous pouvez essayer cette fonctionnalité dès maintenant dans MainActivity.
- Dans
onCreate()à l'intérieur du blocReplyTheme, obtenez les informations d'adaptation de la fenêtre et affichez les classes de taille dans un composableText. Vous pouvez ajouter ce code après l'élémentReplyApp():
MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ReplyTheme {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
ReplyApp(
replyHomeUIState = uiState,
onEmailClick = viewModel::setSelectedEmail
)
val adaptiveInfo = currentWindowAdaptiveInfo()
val sizeClassText =
"${adaptiveInfo.windowSizeClass.windowWidthSizeClass}\n" +
"${adaptiveInfo.windowSizeClass.windowHeightSizeClass}"
Text(
text = sizeClassText,
color = Color.Magenta,
modifier = Modifier.padding(
WindowInsets.safeDrawing.asPaddingValues()
)
)
}
}
}
Si vous exécutez l'application maintenant, les classes de taille de fenêtre s'affichent au-dessus du contenu de l'application. N'hésitez pas à explorer les autres informations fournies dans les infos sur l'adaptation aux fenêtres. Vous pouvez ensuite supprimer ce Text, car il couvre le contenu de l'application et ne sera pas nécessaire pour les prochaines étapes.
4. Navigation dynamique
Vous allez maintenant adapter la navigation de l'application en fonction de l'état et de la taille de l'appareil afin de rendre votre application plus facile à utiliser.
Lorsque les utilisateurs tiennent un téléphone, leurs doigts se trouvent généralement en bas de l'écran. Lorsque les utilisateurs tiennent un appareil pliable ouvert ou une tablette, leurs doigts sont généralement proches des bords. Vos utilisateurs doivent pouvoir naviguer ou interagir avec une application sans devoir placer leurs mains dans une position extrême ni les déplacer.
Lorsque vous concevez votre application et que vous décidez où placer les éléments d'UI interactifs dans votre mise en page, tenez compte des implications ergonomiques des différentes régions de l'écran.
- Quelles zones sont faciles d'accès lorsque vous tenez l'appareil ?
- Quelles zones ne sont accessibles qu'en étendant les doigts, ce qui peut être gênant ?
- Quelles zones sont difficiles à atteindre ou éloignées de l'endroit où l'utilisateur tient l'appareil ?
La navigation est le premier élément avec lequel les utilisateurs interagissent. Elle contient des actions très importantes liées aux parcours utilisateur critiques. Elle doit donc être placée dans les zones les plus faciles d'accès. La bibliothèque adaptative Material fournit plusieurs composants qui vous aident à implémenter la navigation en fonction de la classe de taille de fenêtre de l'appareil.
Barre de navigation inférieure
La barre de navigation inférieure est idéale pour les tailles compactes. En effet, nous tenons naturellement l'appareil de sorte que notre pouce atteigne facilement tous les points de contact inférieurs. Utilisez-la lorsque l'appareil est de taille compacte ou que le pliable est de taille compacte en position pliée.

Rail de navigation
Pour une fenêtre de taille moyenne, le rail de navigation est idéal pour la maniabilité, car le pouce se place naturellement sur le côté de l'appareil. Vous pouvez également combiner un rail de navigation avec un panneau de navigation pour afficher plus d'informations.

Panneau de navigation
Le panneau de navigation permet d'afficher facilement les informations détaillées sur les onglets de navigation. Il est facilement accessible lorsque vous utilisez une tablette ou un appareil plus grand. Il existe deux types de panneaux de navigation : un panneau de navigation modal et un panneau de navigation permanent.
Panneau de navigation modal
Vous pouvez également utiliser un panneau de navigation modal pour les téléphones compacts et les tablettes de taille moyenne. En effet, il peut être développé ou masqué en superposition avec le contenu. Il peut parfois être associé à une barre de navigation.

Panneau de navigation permanent
Vous pouvez utiliser un panneau de navigation permanent pour résoudre les problèmes de navigation sur les grandes tablettes, les Chromebooks et les ordinateurs.

Implémenter la navigation dynamique
Nous allons maintenant passer d'un type de navigation à un autre en fonction de l'état et de la taille de l'appareil.
Actuellement, l'application affiche toujours un NavigationBar sous le contenu de l'écran, quel que soit l'état de l'appareil. Vous pouvez utiliser le composant Material NavigationSuiteScaffold pour basculer automatiquement entre les différents composants de navigation en fonction d'informations telles que la classe de taille de fenêtre actuelle.
- Ajoutez la dépendance Gradle pour obtenir ce composant en mettant à jour le catalogue de versions et le script de compilation de l'application, puis effectuez une synchronisation Gradle :
gradle/libs.versions.toml
[versions]
material3AdaptiveNavSuite = "1.3.0"
[libraries]
androidx-material3-adaptive-navigation-suite = { module = "androidx.compose.material3:material3-adaptive-navigation-suite", version.ref = "material3AdaptiveNavSuite" }
app/build.gradle.kts
dependencies {
implementation(libs.androidx.material3.adaptive.navigation.suite)
}
- Recherchez la fonction composable
ReplyNavigationWrapper()dansReplyApp.ktet remplacez leColumnet son contenu par unNavigationSuiteScaffold:
ReplyApp.kt
@Composable
private fun ReplyNavigationWrapperUI(
content: @Composable () -> Unit = {}
) {
var selectedDestination: ReplyDestination by remember {
mutableStateOf(ReplyDestination.Inbox)
}
NavigationSuiteScaffold(
navigationSuiteItems = {
ReplyDestination.entries.forEach {
item(
selected = it == selectedDestination,
onClick = { /*TODO update selection*/ },
icon = {
Icon(
imageVector = it.icon,
contentDescription = stringResource(it.labelRes)
)
},
label = {
Text(text = stringResource(it.labelRes))
},
)
}
}
) {
content()
}
}
L'argument navigationSuiteItems est un bloc qui vous permet d'ajouter des éléments à l'aide de la fonction item(), comme pour ajouter des éléments dans un LazyColumn. Dans le lambda de fin, ce code appelle le content() transmis en tant qu'argument à ReplyNavigationWrapperUI().
Exécutez l'application sur l'émulateur et essayez de changer de taille entre téléphone, appareil pliable et tablette. Vous verrez la barre de navigation se transformer en rail de navigation et inversement.
Sur les fenêtres très larges, comme sur une tablette en mode paysage, vous pouvez afficher le panneau de navigation permanent. NavigationSuiteScaffold permet d'afficher un tiroir permanent, mais il n'est pas visible dans les valeurs WindowWidthSizeClass actuelles. Toutefois, vous pouvez le faire en apportant une petite modification.
- Ajoutez le code suivant juste avant l'appel à
NavigationSuiteScaffold:
ReplyApp.kt
@Composable
private fun ReplyNavigationWrapperUI(
content: @Composable () -> Unit = {}
) {
var selectedDestination: ReplyDestination by remember {
mutableStateOf(ReplyDestination.Inbox)
}
val windowSize = with(LocalDensity.current) {
currentWindowSize().toSize().toDpSize()
}
val layoutType = if (windowSize.width >= 1200.dp) {
NavigationSuiteType.NavigationDrawer
} else {
NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo(
currentWindowAdaptiveInfo()
)
}
NavigationSuiteScaffold(
layoutType = layoutType,
...
) {
content()
}
}
Ce code obtient d'abord la taille de la fenêtre et la convertit en unités DP à l'aide de currentWindowSize() et LocalDensity.current, puis compare la largeur de la fenêtre pour déterminer le type de mise en page de l'UI de navigation. Si la largeur de la fenêtre est d'au moins 1200.dp, elle utilise NavigationSuiteType.NavigationDrawer. Sinon, le calcul par défaut est utilisé.
Exécutez à nouveau l'application sur l'émulateur redimensionnable pour les différents types d'appareils. Vous remarquerez que la navigation s'adapte en fonction de la taille à chaque fois que la configuration de l'écran change ou que vous dépliez un appareil pliable.

Félicitations, vous connaissez les types de navigation compatibles avec les différents types de tailles et états de fenêtre.
Dans la section suivante, vous allez apprendre à exploiter les zones d'écran restantes au lieu d'étirer un même élément de liste d'un bord à l'autre.
5. Utilisation de l'espace à l'écran
Que vous exécutiez l'application sur une petite tablette, un appareil déplié ou une grande tablette, l'écran s'étire pour occuper l'espace restant. Assurez-vous d'exploiter tout cet espace à l'écran pour afficher d'autres d'informations, comme dans cette application qui réunit la messagerie et les fils de discussion sur une même page.
Material 3 définit trois mises en page canoniques, chacune ayant des configurations pour les classes de taille de fenêtre compacte, moyenne et agrandie. La mise en page canonique Liste/Détail est idéale pour ce cas d'utilisation et est disponible dans Compose sous la forme ListDetailPaneScaffold.
- Pour obtenir ce composant, ajoutez les dépendances suivantes et synchronisez Gradle :
gradle/libs.versions.toml
[libraries]
androidx-material3-adaptive-layout = { module = "androidx.compose.material3.adaptive:adaptive-layout", version.ref = "material3Adaptive" }
androidx-material3-adaptive-navigation = { module = "androidx.compose.material3.adaptive:adaptive-navigation", version.ref = "material3Adaptive" }
app/build.gradle.kts
dependencies {
implementation(libs.androidx.material3.adaptive.layout)
implementation(libs.androidx.material3.adaptive.navigation)
}
- Recherchez la fonction composable
ReplyAppContent()dansReplyApp.kt, qui n'affiche actuellement que le volet de liste en appelantReplyListPane(). Remplacez cette implémentation parListDetailPaneScaffolden insérant le code suivant. Comme il s'agit d'une API expérimentale, vous devez également ajouter l'annotation@OptInà la fonctionReplyAppContent():
ReplyApp.kt
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Composable
fun ReplyAppContent(
replyHomeUIState: ReplyHomeUIState,
onEmailClick: (Email) -> Unit,
) {
val navigator = rememberListDetailPaneScaffoldNavigator<Long>()
ListDetailPaneScaffold(
directive = navigator.scaffoldDirective,
value = navigator.scaffoldValue,
listPane = {
ReplyListPane(replyHomeUIState, onEmailClick)
},
detailPane = {
ReplyDetailPane(replyHomeUIState.emails.first())
}
)
}
Ce code crée d'abord un navigateur à l'aide de rememberListDetailPaneNavigator. Le navigateur permet de contrôler le volet affiché et le contenu qui doit y figurer, comme nous le verrons plus loin.
ListDetailPaneScaffold affichera deux volets lorsque la classe de taille de fenêtre en largeur est "étendue". Sinon, il affichera l'un ou l'autre des volets en fonction des valeurs fournies pour deux paramètres : la directive de structure et la valeur de structure. Pour obtenir le comportement par défaut, ce code utilise la directive scaffold et la valeur scaffold fournie par le navigateur.
Les autres paramètres requis sont des lambdas composables pour les volets. ReplyListPane() et ReplyDetailPane() (disponibles dans ReplyListContent.kt) permettent de renseigner les rôles des volets Liste et Détails, respectivement. ReplyDetailPane() attend un argument d'adresse e-mail. Pour l'instant, ce code utilise donc la première adresse e-mail de la liste des adresses e-mail dans ReplyHomeUIState.
Exécutez l'application et passez à la vue pliable ou tablette de l'émulateur (vous devrez peut-être également changer l'orientation) pour afficher la mise en page à deux volets. C'est déjà beaucoup mieux !
Abordons maintenant certains des comportements souhaités de cet écran. Lorsque l'utilisateur appuie sur un e-mail dans le volet de liste, il doit s'afficher dans le volet de détails avec toutes les réponses. Actuellement, l'application ne garde pas la trace de l'e-mail sélectionné et rien ne se passe lorsque vous appuyez sur un élément. Le meilleur endroit pour conserver ces informations est avec le reste de l'état de l'UI dans ReplyHomeUIState.
- Ouvrez
ReplyHomeViewModel.ktet recherchez la classe de donnéesReplyHomeUIState. Ajoutez une propriété pour l'e-mail sélectionné, avec une valeur par défaut denull:
ReplyHomeViewModel.kt
data class ReplyHomeUIState(
val emails : List<Email> = emptyList(),
val selectedEmail: Email? = null,
val loading: Boolean = false,
val error: String? = null
)
- Dans le même fichier,
ReplyHomeViewModelcomporte une fonctionsetSelectedEmail()appelée lorsque l'utilisateur appuie sur un élément de la liste. Modifiez cette fonction pour copier l'état de l'UI et enregistrer l'adresse e-mail sélectionnée :
ReplyHomeViewModel.kt
fun setSelectedEmail(email: Email) {
_uiState.update {
it.copy(selectedEmail = email)
}
}
Il faut également réfléchir à ce qui se passe avant que l'utilisateur n'appuie sur un élément et que l'adresse e-mail sélectionnée soit null. Que doit afficher le volet Détails ? Il existe plusieurs façons de gérer ce cas, par exemple en affichant le premier élément de la liste par défaut.
- Dans le même fichier, modifiez la fonction
observeEmails(). Lorsque la liste des e-mails est chargée, si l'état précédent de l'UI ne comportait pas d'e-mail sélectionné, définissez-le sur le premier élément :
ReplyHomeViewModel.kt
private fun observeEmails() {
viewModelScope.launch {
emailsRepository.getAllEmails()
.catch { ex ->
_uiState.value = ReplyHomeUIState(error = ex.message)
}
.collect { emails ->
val currentSelection = _uiState.value.selectedEmail
_uiState.value = ReplyHomeUIState(
emails = emails,
selectedEmail = currentSelection ?: emails.first()
)
}
}
}
- Revenez à
ReplyApp.ktet utilisez l'adresse e-mail sélectionnée, si elle est disponible, pour remplir le contenu du volet Détails :
ReplyApp.kt
ListDetailPaneScaffold(
// ...
detailPane = {
if (replyHomeUIState.selectedEmail != null) {
ReplyDetailPane(replyHomeUIState.selectedEmail)
}
}
)
Exécutez de nouveau l'application et passez l'émulateur à la taille d'une tablette. Vous verrez qu'en appuyant sur un élément de la liste, le contenu du volet de détails est mis à jour.
Cela fonctionne très bien lorsque les deux volets sont visibles, mais lorsque la fenêtre n'a de la place que pour un seul volet, il semble que rien ne se passe lorsque vous appuyez sur un élément. Essayez de passer à la vue Téléphone ou Appareil pliable en mode Portrait dans l'émulateur. Vous remarquerez que seul le volet de liste est visible, même après avoir appuyé sur un élément. En effet, même si l'adresse e-mail sélectionnée est mise à jour, ListDetailPaneScaffold conserve la mise au point sur le volet de liste dans ces configurations.
- Pour résoudre ce problème, insérez le code suivant en tant que lambda transmis à
ReplyListPane:
ReplyApp.kt
ListDetailPaneScaffold(
// ...
listPane = {
ReplyListPane(
replyHomeUIState = replyHomeUIState,
onEmailClick = { email ->
onEmailClick(email)
navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, email.id)
}
)
},
// ...
)
Ce lambda utilise le navigateur créé précédemment pour ajouter un comportement supplémentaire lorsqu'un élément est cliqué. Il appellera le lambda d'origine transmis à cette fonction, puis appellera également navigator.navigateTo() en spécifiant le volet à afficher. Chaque volet du canevas est associé à un rôle. Pour le volet Détails, il s'agit de ListDetailPaneScaffoldRole.Detail. Dans les fenêtres plus petites, l'application aura l'air d'avoir avancé.
L'application doit également gérer ce qui se passe lorsque l'utilisateur appuie sur le bouton Retour depuis le volet Détails. Ce comportement varie selon qu'un ou deux volets sont visibles.
- Ajoutez le code suivant pour prendre en charge la navigation vers l'arrière.
ReplyApp.kt
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Composable
fun ReplyAppContent(
replyHomeUIState: ReplyHomeUIState,
onEmailClick: (Email) -> Unit,
) {
val navigator = rememberListDetailPaneScaffoldNavigator<Long>()
BackHandler(navigator.canNavigateBack()) {
navigator.navigateBack()
}
ListDetailPaneScaffold(
directive = navigator.scaffoldDirective,
value = navigator.scaffoldValue,
listPane = {
AnimatedPane {
ReplyListPane(
replyHomeUIState = replyHomeUIState,
onEmailClick = { email ->
onEmailClick(email)
navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, email.id)
}
)
}
},
detailPane = {
AnimatedPane {
if (replyHomeUIState.selectedEmail != null) {
ReplyDetailPane(replyHomeUIState.selectedEmail)
}
}
}
)
}
Le navigateur connaît l'état complet de ListDetailPaneScaffold, si la navigation à l'arrière est possible et ce qu'il faut faire dans tous ces scénarios. Ce code crée un BackHandler qui est activé chaque fois que le navigateur peut revenir en arrière et appelle navigateBack() à l'intérieur du lambda. De plus, pour rendre la transition entre les volets beaucoup plus fluide, chaque volet est encapsulé dans un composable AnimatedPane().
Exécutez à nouveau l'application sur un émulateur redimensionnable pour les différents types d'appareils. Vous remarquerez que la navigation et le contenu de l'écran s'adaptent de façon dynamique en fonction de l'état de l'appareil à chaque fois que la configuration de l'écran change ou que vous dépliez un appareil pliable. Essayez également d'appuyer sur des e-mails dans le volet de liste et observez le comportement de la mise en page sur différents écrans, en affichant les deux volets côte à côte ou en animant la transition entre eux de manière fluide.

Félicitations, vous avez adapté votre application à tous les états et les tailles d'appareils. Essayez d'exécuter l'application sur des appareils pliables, des tablettes ou d'autres appareils mobiles.
6. Félicitations
Félicitations ! Vous avez terminé cet atelier de programmation et appris à créer des applications adaptatives avec Jetpack Compose.
Vous avez découvert comment vérifier la taille et l'état de pliage d'un appareil, et comment adapter l'UI, l'outil de navigation et d'autres fonctions en conséquence. Vous avez également appris comment l'adaptabilité améliore la maniabilité et l'expérience utilisateur.
Étape suivante
Consultez les autres ateliers de programmation du parcours Compose.
Applications exemples
- Les exemples Compose constituent un ensemble d'applications intégrant les bonnes pratiques expliquées dans des ateliers de programmation.
Documents de référence
- Material 3 Adaptive design (Guide adaptatif Material 3)
- Designing for large screens (Conception pour les grands écrans)
- Introducing Material Theme Builder (Outil de création de thèmes Material)
- Material 3 Introducing Material You (Material 3 et présentation de Material You)