Créer une mise en page liste/détails

Liste/détails est un modèle d'interface utilisateur qui se compose d'une mise en page à deux volets dans laquelle un volet présente une liste d'éléments, et un autre affiche les détails des éléments sélectionnés dans la liste.

Ce modèle est particulièrement utile pour les applications qui fournissent des informations détaillées sur les éléments de grandes collections, par exemple un client de messagerie contenant une liste d'e-mails et le contenu détaillé de chaque e-mail. Vous pouvez également utiliser la fonctionnalité Liste/Détail pour les chemins moins critiques, tels que la division des préférences d'application en une liste de catégories avec les préférences pour chaque catégorie dans le volet de détails.

Implémenter un modèle d'interface utilisateur avec ListDetailPaneScaffold

ListDetailPaneScaffold est un composable qui simplifie l'implémentation du modèle liste/détails dans votre application. Un échafaudage liste/détails peut comporter jusqu'à trois volets: un volet Liste, un volet Détails et un volet supplémentaire facultatif. L'échafaudage gère les calculs d'espace à l'écran. Lorsqu'une taille d'écran suffisante est disponible, le volet de vue détaillée s'affiche à côté du volet de liste. Sur les petits écrans, l'échafaudage passe automatiquement à l'affichage en plein écran du volet de liste ou de vue détaillée.

Volet d'informations affiché à côté de la page de la liste.
Figure 1. Lorsque la taille d'écran disponible est suffisante, le volet de détails s'affiche à côté du volet de liste.
Une fois qu'un élément est sélectionné, le volet des détails occupe la totalité de l'écran.
Figure 2. Lorsque la taille de l'écran est limitée, le volet des détails (puisque un élément a été sélectionné) occupe la totalité de l'espace.

Déclarer des dépendances

ListDetailPaneScaffold fait partie de la bibliothèque de mises en page adaptatives Material 3.

Votre application doit inclure des dépendances pour trois bibliothèques Material 3 associées:

  • adaptatif : composants de bas niveau, tels que HingeInfo et Posture
  • adaptive-layout : mises en page adaptatives telles que ListDetailPaneScaffold et SupportingPaneScaffold
    • adaptive-navigation (navigation adaptative) : composables permettant de naviguer dans les volets et entre eux

Ajoutez les dépendances au fichier build.gradle de votre application ou module:

Kotlin


implementation("androidx.compose.material3.adaptive:adaptive:1.0.0-alpha12")
implementation("androidx.compose.material3.adaptive:adaptive-layout:1.0.0-alpha12")
implementation("androidx.compose.material3.adaptive:adaptive-navigation:1.0.0-alpha12")

Groovy


implementation 'androidx.compose.material3.adaptive:adaptive:1.0.0-alpha12'
implementation 'androidx.compose.material3.adaptive:adaptive-layout:1.0.0-alpha12'
implementation 'androidx.compose.material3.adaptive:adaptive-navigation:1.0.0-alpha12'

Utilisation de base

Implémentez ListDetailPaneScaffold comme suit:

  1. Utilisez une classe qui représente le contenu à sélectionner. Cette classe doit être Parcelable pour permettre l'enregistrement et la restauration de l'élément de liste sélectionné. Utilisez le plug-in Kotlin-parcelize pour générer le code automatiquement.

    @Parcelize
    class MyItem(val id: Int) : Parcelable

  2. Créez un ThreePaneScaffoldNavigator avec rememberListDetailPaneScaffoldNavigator et ajoutez un BackHandler. Ce navigateur permet de naviguer entre les volets de liste, de détails et supplémentaires. En déclarant un type générique, le navigateur suit également l'état de l'échafaudage (c'est-à-dire le MyItem affiché). Ce type étant parcelable, l'état peut être enregistré et restauré par le navigateur pour gérer automatiquement les modifications de configuration. BackHandler permet de revenir en arrière à l'aide du geste ou du bouton Retour du système. Le comportement attendu du bouton "Retour" pour un élément ListDetailPaneScaffold dépend de la taille de la fenêtre et de la valeur d'échafaudage actuelle. Si ListDetailPaneScaffold permet de revenir à l'état actuel, canNavigateBack() est true, ce qui active BackHandler.

    val navigator = rememberListDetailPaneScaffoldNavigator<MyItem>()
    
    BackHandler(navigator.canNavigateBack()) {
        navigator.navigateBack()
    }

  3. Transmettez le scaffoldState de navigator au composable ListDetailPaneScaffold.

    ListDetailPaneScaffold(
        directive = navigator.scaffoldDirective,
        value = navigator.scaffoldValue,
        // ...
    )

  4. Fournissez l'implémentation de votre volet de liste à ListDetailPaneScaffold. Utilisez AnimatedPane pour appliquer les animations de volet par défaut pendant la navigation. Utilisez ensuite ThreePaneScaffoldNavigator pour accéder au volet Détails, ListDetailPaneScaffoldRole.Detail, et afficher l'élément transmis.

    ListDetailPaneScaffold(
        directive = navigator.scaffoldDirective,
        value = navigator.scaffoldValue,
        listPane = {
            AnimatedPane {
                MyList(
                    onItemClick = { item ->
                        // Navigate to the detail pane with the passed item
                        navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, item)
                    }
                )
            }
        },
        // ...
    )

  5. Incluez l'implémentation du volet de détails dans ListDetailPaneScaffold. Une fois la navigation terminée, currentDestination contient le volet auquel votre application a accédé, y compris le contenu affiché dans le volet. La propriété content est du même type que celui spécifié dans l'appel de mémorisation d'origine (MyItem dans cet exemple). Vous pouvez donc également accéder à la propriété pour toutes les données que vous devez afficher.

    ListDetailPaneScaffold(
        directive = navigator.scaffoldDirective,
        value = navigator.scaffoldValue,
        listPane =
        // ...
        detailPane = {
            AnimatedPane {
                navigator.currentDestination?.content?.let {
                    MyDetails(it)
                }
            }
        },
    )

Une fois que vous avez suivi la procédure ci-dessus, votre code doit se présenter comme suit:

val navigator = rememberListDetailPaneScaffoldNavigator<MyItem>()

BackHandler(navigator.canNavigateBack()) {
    navigator.navigateBack()
}

ListDetailPaneScaffold(
    directive = navigator.scaffoldDirective,
    value = navigator.scaffoldValue,
    listPane = {
        AnimatedPane {
            MyList(
                onItemClick = { item ->
                    // Navigate to the detail pane with the passed item
                    navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, item)
                },
            )
        }
    },
    detailPane = {
        AnimatedPane {
            // Show the detail pane content if selected item is available
            navigator.currentDestination?.content?.let {
                MyDetails(it)
            }
        }
    },
)