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'interface utilisateur de votre application doit être responsive afin de tenir compte des 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 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é.
- Comment utiliser les composants Material 3 pour offrir la meilleure expérience possible pour chaque taille de fenêtre.
Prérequis
- La dernière version stable d'Android Studio
- Un 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 (par exemple,
Row
etColumn
) - Connaissances de base sur les modificateurs (par exemple,
Modifier.padding()
)
Dans cet atelier de programmation, vous allez utiliser 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, vous pouvez suivre l'atelier de programmation sur les principes de base de Jetpack Compose avant de le terminer.
Ce que vous allez faire
- Une application cliente de messagerie interactive appelée Reply, qui utilise les bonnes pratiques pour 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épertoireAdaptiveUiCodelab
contenantbuild.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 dans ce package:
MainActivity.kt
: activité de point d'entrée à partir de laquelle vous démarrez votre application.ReplyApp.kt
: contient les composables de l'UI de l'écran principal.ReplyHomeViewModel.kt
: fournit les données et l'état de l'interface utilisateur 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 le mettrez à jour pour profiter de l'espace à l'écran, augmenter la facilité d'utilisation et améliorer l'expérience utilisateur globale.
3. Assurer l'adaptation des applications
Cette section explique en quoi consiste l'adaptation des applications et quels sont les composants fournis par Material 3 pour vous faciliter la tâche. Il couvre également 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 examiner les principes de base des tailles de fenêtre, des positions de pliage et des différents types d'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 approprié pour modifier l'interface utilisateur de votre application, nous avons défini des valeurs de point d'arrêt qui permettent de classer les appareils en classes de tailles prédéfinies (compacte, moyenne et étendue), appelées classes de taille 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 utiliserez donc également des classes de largeur.
États de pliage
Les appareils pliables présentent d'autres 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 et la rendre inappropriée pour l'affichage de contenu. ils peuvent aussi être séparés, ce qui signifie que deux écrans physiques distincts s'affichent 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 positions physiques en fonction de l'orientation du pli: position à plat (pli horizontal, illustré à droite dans l'image ci-dessus) et position du livre (pli vertical).
En savoir plus sur les positions et les charnières de pliage
Tous ces éléments sont à prendre en compte lors de l'implémentation de mises en page adaptatives compatibles avec les appareils pliables.
Obtenir des informations adaptatives
La bibliothèque adaptive
Material3 fournit un accès pratique 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 de catalogue de versions:
gradle/libs.versions.toml
[versions]
material3Adaptive = "1.0.0-beta01"
[libraries]
androidx-material3-adaptive = { module = "androidx.compose.material3.adaptive:adaptive", version.ref = "material3Adaptive" }
- Dans le fichier de compilation 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 quel champ d'application composable, vous pouvez utiliser currentWindowAdaptiveInfo()
pour obtenir un objet WindowAdaptiveInfo
contenant des informations telles que la classe de taille de fenêtre actuelle et si l'appareil est dans une position pliable (position à plat, par exemple).
Vous pouvez essayer dans MainActivity
.
- Dans
onCreate()
, à l'intérieur du blocReplyTheme
, obtenez les informations adaptatives de la fenêtre et affichez les classes de taille dans un composableText
. Vous pouvez ajouter ceci 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(20.dp)
)
}
}
}
Si vous exécutez l'application maintenant, les classes de taille de fenêtre s'afficheront sur le contenu de l'application. N'hésitez pas à explorer les autres informations fournies dans les informations adaptatives des fenêtres. Vous pouvez ensuite supprimer ce Text
, car il couvre le contenu de l'application. Vous n'en aurez pas besoin pour les étapes suivantes.
4. Navigation dynamique
Vous allez maintenant adapter la navigation de l'application à mesure que l'état et la taille de l'appareil changent afin de faciliter son utilisation.
Lorsque les utilisateurs tiennent un téléphone, leurs doigts sont 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 côtés. Vos utilisateurs doivent pouvoir naviguer dans une application ou interagir avec elle sans avoir à placer les mains dans une position extrême ni à les déplacer.
Lorsque vous concevez votre application et décidez où placer les éléments interactifs de l'interface utilisateur dans votre mise en page, tenez compte des implications ergonomiques des différentes régions de l'écran.
- Quelles zones peuvent être facilement accessibles lorsque vous tenez l'appareil ?
- Quelles zones ne peuvent être atteintes qu'en étendant les doigts, ce qui peut être gênant ?
- Quelles zones sont difficiles à atteindre ou sont éloignées de l'endroit où l'utilisateur tient l'appareil ?
La navigation est la première chose avec laquelle les utilisateurs interagissent. Elle contient des actions très importantes en lien avec les parcours utilisateur critiques. Elle doit donc être placée dans les zones les plus accessibles. La bibliothèque adaptative de 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 largeur moyenne, le rail de navigation est idéal pour la maniabilité, car notre pouce tombe naturellement sur le côté de l'appareil. Vous pouvez également associer un rail de navigation à 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 utiliser un panneau de navigation modal pour les téléphones et tablettes compacts à moyennes, car il peut être développé ou masqué en superposition sur le contenu. Cette fonctionnalité peut parfois être associée à un rail de navigation.
Panneau de navigation permanent
Vous pouvez utiliser un panneau de navigation permanent pour une navigation fixe sur les grandes tablettes, les Chromebooks et les ordinateurs.
Implémenter la navigation dynamique
Vous allez 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 une NavigationBar
sous le contenu de l'écran, quel que soit l'état de l'appareil. À la place, 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-beta01"
[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.kt
, puis remplacez leColumn
et 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()
, de la même manière que l'ajout d'éléments dans une 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, pliable et tablette. La barre de navigation se transforme en rail de navigation, puis à l'arrière.
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 panneau permanent, bien qu'il ne figure dans aucune des valeurs WindowWidthSizeClass
actuelles. Cependant, vous pouvez le faire avec une légère 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 de DP à l'aide de currentWindowSize()
et LocalDensity.current
, puis compare la largeur de la fenêtre pour décider du type de mise en page de l'UI de navigation. Si la largeur de la fenêtre est d'au moins 1200.dp
, la valeur NavigationSuiteType.NavigationDrawer
est utilisée. Sinon, le calcul par défaut est appliqué.
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 avez découvert les différents types de navigation pour prendre en charge différents types de tailles et d'é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 standards qui ont chacune des configurations pour les classes de taille de fenêtre compacte, moyenne et grande. La mise en page canonique Détail de la liste est idéale pour ce cas d'utilisation. Elle est disponible dans Compose en tant que ListDetailPaneScaffold
.
- Obtenez ce composant en ajoutant les dépendances suivantes et en effectuant une synchronisation 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 parListDetailPaneScaffold
en insérant le code suivant. Comme il s'agit d'une API expérimentale, vous allez é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 à représenter dans ce volet. Nous en reparlerons plus tard.
ListDetailPaneScaffold
affiche deux volets lorsque la classe de largeur de fenêtre est étendue. Sinon, il affichera un volet ou l'autre en fonction des valeurs fournies pour deux paramètres: la directive d'échafaudage et la valeur d'échafaudage. Pour obtenir le comportement par défaut, ce code utilise la directive d'échafaudage et la valeur d'échafaudage fournie par le navigateur.
Les paramètres obligatoires restants sont des lambdas composables pour les volets. ReplyListPane()
et ReplyDetailPane()
(disponibles dans ReplyListContent.kt
) permettent respectivement de remplir les rôles des volets de liste et de détail. 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 dans ReplyHomeUIState
.
Exécutez l'application et basculez la vue de l'émulateur sur pliable ou tablette (vous devrez peut-être également changer l'orientation) pour afficher la mise en page à deux volets. C'est déjà beaucoup mieux qu'avant !
Voyons maintenant certains des comportements souhaités sur cet écran. Lorsque l'utilisateur appuie sur un e-mail dans le volet de liste, celui-ci doit s'afficher dans le volet des détails avec toutes les réponses. Actuellement, l'application n'effectue pas le suivi de l'e-mail sélectionné et le fait d'appuyer sur un élément n'a aucun effet. Le meilleur endroit pour conserver ces informations est le reste de l'état de l'UI dans ReplyHomeUIState
.
- Ouvrez
ReplyHomeViewModel.kt
et recherchez la classe de donnéesReplyHomeUIState
. Ajoutez une propriété pour l'adresse e-mail sélectionnée, 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,
ReplyHomeViewModel
comporte une fonctionsetSelectedEmail()
qui est appelée lorsque l'utilisateur appuie sur un élément de la liste. Modifiez cette fonction pour copier l'état de l'interface utilisateur et enregistrer l'e-mail sélectionné:
ReplyHomeViewModel.kt
fun setSelectedEmail(email: Email) {
_uiState.update {
it.copy(selectedEmail = email)
}
}
Vous devez prendre en compte ce qui se passe avant que l'utilisateur n'ait appuyé sur un élément et que l'adresse e-mail sélectionnée est null
. Que doit afficher le volet Détails ? Il existe plusieurs façons de gérer ce cas, comme afficher par défaut le premier élément de la liste.
- Dans le même fichier, modifiez la fonction
observeEmails()
. Lorsque la liste d'e-mails est chargée, si l'ancien état de l'interface utilisateur ne comportait pas d'adresse e-mail sélectionnée, 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.kt
et utilisez l'e-mail sélectionné, s'il est disponible, pour remplir le contenu du volet Détails:
ReplyApp.kt
ListDetailPaneScaffold(
// ...
detailPane = {
if (replyHomeUIState.selectedEmail != null) {
ReplyDetailPane(replyHomeUIState.selectedEmail)
}
}
)
Exécutez à nouveau l'application et faites passer l'émulateur à la taille d'une tablette. Vous verrez que le fait d'appuyer sur un élément de la liste met à jour le contenu du volet de détails.
Cela fonctionne très bien lorsque les deux volets sont visibles, mais lorsque la fenêtre n'a de place pour afficher qu'un seul volet, il semble que rien ne se passe lorsque vous appuyez sur un élément. Essayez de basculer l'affichage de l'émulateur vers un téléphone ou un appareil pliable en mode portrait. Notez 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
reste actif dans 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 utilisateur clique sur un élément. Elle appellera le lambda d'origine transmis à cette fonction, puis appelle également navigator.navigateTo()
en spécifiant le volet à afficher. Chaque volet de l'échafaudage est associé à un rôle. Pour le volet des détails, il s'agit de ListDetailPaneScaffoldRole.Detail
. Sur les fenêtres de petite taille, cela donne l'impression que l'application a été avancée.
L'application doit également gérer ce qui se passe lorsque l'utilisateur appuie sur le bouton "Retour" dans le volet de détails. Ce comportement varie selon qu'un ou deux volets sont visibles.
- Prenez en charge la navigation vers l'arrière en ajoutant le code suivant.
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 vers 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 qui appelle navigateBack()
dans le lambda. De plus, pour faciliter la transition entre les volets, chacun d'eux est encapsulé dans un composable AnimatedPane()
.
Exécutez à nouveau l'application sur un émulateur redimensionnable pour tous les différents types d'appareils. Notez que chaque fois que la configuration de l'écran change ou que vous dépliez un appareil pliable, la navigation et le contenu de l'écran changent de manière dynamique en fonction de l'état de l'appareil. Appuyez également sur les e-mails dans le volet de liste pour observer le comportement de la mise en page sur différents écrans, en affichant les deux volets côte à côte ou en créant une animation fluide entre eux.
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 à rendre 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 sont une collection de nombreuses 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)