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

Liste/détails est un modèle d'interface utilisateur composé d'une mise en page à deux volets dans laquelle un volet présente une liste d'éléments et un autre volet 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 sur les éléments de grandes collections, comme un client de messagerie qui contient une liste d'e-mails et le contenu détaillé de chaque e-mail. Vous pouvez aussi utiliser la vue liste/détails pour les chemins moins critiques, comme diviser l'application préférences dans une liste de catégories, avec les préférences pour chaque catégorie dans le volet Détails.

Implémenter un modèle d'UI avec ListDetailPaneScaffold

ListDetailPaneScaffold est un composable qui simplifie l'implémentation de le schéma "Liste et vue détaillée" dans votre application. Une structure liste/détails peut comporter jusqu'à trois volets: un volet de liste, un volet de détails et un volet supplémentaire facultatif. La échafaudage gère les calculs d'espace à l'écran. Lorsque la taille de l'écran est suffisante disponible, le volet Détails s'affiche à côté du volet de liste. Sur petit écran tailles d'écran, l'échafaudage passe automatiquement à l'affichage de la liste volet de détails en plein écran.

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

Déclarer des dépendances

ListDetailPaneScaffold fait partie de la mise en page adaptative Material 3 bibliothèque.

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

Kotlin


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

Groovy


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

  • adaptatif : éléments de base de bas niveau tels que HingeInfo et Posture
  • adaptive-layout : mises en page adaptatives telles que ListDetailPaneScaffold et SupportingPaneScaffold
  • adaptive-navigation : composables permettant de naviguer dans et entre les volets

Utilisation de base

Implémentez ListDetailPaneScaffold comme suit:

  1. Utilisez une classe représentant le contenu à sélectionner. Ce cours doit être Parcelable pour permettre l'enregistrement puis restaure l'élément de liste sélectionné. Utilisez la commande kotlin-parcelize plug-in afin de générer le code automatiquement.

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

  2. Créer un ThreePaneScaffoldNavigator avec rememberListDetailPaneScaffoldNavigator et ajoutez un élément BackHandler. Ce permet de naviguer entre les volets de liste, de détail et supplémentaire. Par déclarant un type générique, le navigateur suit également l'état échafaudage (c'est-à-dire l'élément MyItem affiché). Puisque ce type est parcelable, l'état peut être enregistré et restauré par le navigateur automatiquement les modifications de configuration. La BackHandler permet de revenir en arrière à l'aide du geste Retour du système ou . Comportement attendu du bouton "Retour" lors d'une ListDetailPaneScaffold dépend de la taille de la fenêtre et de l'échafaudage actuel . Si ListDetailPaneScaffold permet de revenir en arrière avec l'état actuel, alors canNavigateBack() est true, ce qui permet BackHandler

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

  3. Transmettez le scaffoldState de navigator à la 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 lors de la navigation. Ensuite, utilisez ThreePaneScaffoldNavigator pour accéder au volet de détails, ListDetailPaneScaffoldRole.Detail, puis 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 de votre volet de détails dans ListDetailPaneScaffold. Une fois la navigation terminée, currentDestination contient le volet dans lequel auquel l'application accède, y compris le contenu affiché dans le volet. La La propriété content est du même type que celui spécifié dans l'appel remember d'origine (MyItem dans cet exemple). Vous pouvez donc 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 les étapes ci-dessus implémentées, votre code doit ressembler à ceci:

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)
            }
        }
    },
)