Créer une mise en page de volet secondaire

La mise en page d'un volet secondaire permet à l'utilisateur de rester concentré sur le contenu principal de l'application tout en affichant des informations complémentaires pertinentes. Par exemple, le volet principal peut afficher des informations sur un film, tandis que le volet secondaire liste des films similaires, des films du même réalisateur ou des œuvres mettant en scène les mêmes acteurs.

Pour en savoir plus, consultez les consignes relatives au volet de prise en charge Material 3.

Implémenter un volet secondaire avec un échafaudage

NavigableSupportingPaneScaffold est un composable qui simplifie l'implémentation d'une mise en page de volet de complément dans Jetpack Compose. Il encapsule SupportingPaneScaffold et ajoute la gestion intégrée de la navigation et de la prévisualisation du Retour.

Une structure de volet secondaire peut comporter jusqu'à trois volets :

  • Volet principal : affiche le contenu principal.
  • Volet secondaire : fournit du contexte ou des outils supplémentaires liés au volet principal.
  • Volet supplémentaire (facultatif) : utilisé pour le contenu supplémentaire si nécessaire.

L'échafaudage s'adapte en fonction de la taille de la fenêtre :

  • Dans les grandes fenêtres, les volets principal et secondaire s'affichent côte à côte.
  • Dans les petites fenêtres, un seul volet est visible à la fois, et il change à mesure que les utilisateurs naviguent.

    Contenu principal occupant la majeure partie de l'écran, avec du contenu secondaire à côté.
    Figure 1 : Mise en page avec volet secondaire.

Ajouter des dépendances

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

Ajoutez les trois dépendances associées 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'
  • adaptive : blocs de construction de bas niveau tels que HingeInfo et Posture

  • adaptive-layout : mises en page adaptatives telles que ListDetailPaneScaffold et SupportingPaneScaffold

  • adaptive-navigation : composables pour naviguer dans et entre les volets, ainsi que des mises en page adaptatives qui prennent en charge la navigation par défaut, telles que NavigableListDetailPaneScaffold et NavigableSupportingPaneScaffold

Assurez-vous que votre projet inclut compose-material3-adaptive version 1.1.0-beta1 ou version ultérieure.

Activer la prévisualisation du geste Retour

Pour activer les animations de prévisualisation du geste Retour dans Android 15 ou version antérieure, vous devez activer la prise en charge de la prévisualisation du geste Retour. Pour l'activer, ajoutez android:enableOnBackInvokedCallback="true" à la balise <application> ou aux balises <activity> individuelles de votre fichier AndroidManifest.xml.

Une fois que votre application cible Android 16 (niveau d'API 36) ou version ultérieure, la prévisualisation du Retour est activée par défaut.

Créer un navigateur

Dans les petites fenêtres, un seul volet s'affiche à la fois. Utilisez donc un ThreePaneScaffoldNavigator pour passer d'un volet à l'autre. Créez une instance du navigateur avec rememberSupportingPaneScaffoldNavigator.

val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator()
val scope = rememberCoroutineScope()

Transmettre le navigateur au scaffold

Le scaffold nécessite un ThreePaneScaffoldNavigator, qui est une interface représentant l'état du scaffold, le ThreePaneScaffoldValue et un PaneScaffoldDirective.

NavigableSupportingPaneScaffold(
    navigator = scaffoldNavigator,
    mainPane = { /*...*/ },
    supportingPane = { /*...*/ },
)

Le volet principal et le volet secondaire sont des composables contenant votre contenu. Utilisez AnimatedPane pour appliquer les animations de volet par défaut lors de la navigation. Utilisez la valeur du scaffold pour vérifier si le volet d'assistance est masqué. Si c'est le cas, affichez un bouton qui appelle navigateTo(SupportingPaneScaffoldRole.Supporting) pour afficher le volet d'assistance.

Voici une implémentation complète du scaffold :

val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator()
val scope = rememberCoroutineScope()

NavigableSupportingPaneScaffold(
    navigator = scaffoldNavigator,
    mainPane = {
        AnimatedPane(
            modifier = Modifier
                .safeContentPadding()
                .background(Color.Red)
        ) {
            if (scaffoldNavigator.scaffoldValue[SupportingPaneScaffoldRole.Supporting] == PaneAdaptedValue.Hidden) {
                Button(
                    modifier = Modifier
                        .wrapContentSize(),
                    onClick = {
                        scope.launch {
                            scaffoldNavigator.navigateTo(SupportingPaneScaffoldRole.Supporting)
                        }
                    }
                ) {
                    Text("Show supporting pane")
                }
            } else {
                Text("Supporting pane is shown")
            }
        }
    },
    supportingPane = {
        AnimatedPane(modifier = Modifier.safeContentPadding()) {
            Text("Supporting pane")
        }
    }
)

Extraire les composables de volet

Extrayez les volets individuels d'un SupportingPaneScaffold dans leurs propres composables pour les rendre réutilisables et testables. Utilisez ThreePaneScaffoldScope pour accéder à AnimatedPane si vous souhaitez utiliser les animations par défaut :

@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Composable
fun ThreePaneScaffoldPaneScope.MainPane(
    shouldShowSupportingPaneButton: Boolean,
    onNavigateToSupportingPane: () -> Unit,
    modifier: Modifier = Modifier,
) {
    AnimatedPane(
        modifier = modifier.safeContentPadding()
    ) {
        // Main pane content
        if (shouldShowSupportingPaneButton) {
            Button(onClick = onNavigateToSupportingPane) {
                Text("Show supporting pane")
            }
        } else {
            Text("Supporting pane is shown")
        }
    }
}

@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Composable
fun ThreePaneScaffoldPaneScope.SupportingPane(
    modifier: Modifier = Modifier,
) {
    AnimatedPane(modifier = modifier.safeContentPadding()) {
        // Supporting pane content
        Text("This is the supporting pane")
    }
}

L'extraction des volets dans des composables simplifie l'utilisation de SupportingPaneScaffold (comparez ce qui suit à l'implémentation complète du scaffold dans la section précédente) :

val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator()
val scope = rememberCoroutineScope()

NavigableSupportingPaneScaffold(
    navigator = scaffoldNavigator,
    mainPane = {
        MainPane(
            shouldShowSupportingPaneButton = scaffoldNavigator.scaffoldValue.secondary == PaneAdaptedValue.Hidden,
            onNavigateToSupportingPane = {
                scope.launch {
                    scaffoldNavigator.navigateTo(ThreePaneScaffoldRole.Secondary)
                }
            }
        )
    },
    supportingPane = { SupportingPane() },
)

Si vous avez besoin de plus de contrôle sur des aspects spécifiques du scaffold, envisagez d'utiliser SupportingPaneScaffold au lieu de NavigableSupportingPaneScaffold. Cette méthode accepte PaneScaffoldDirective et ThreePaneScaffoldValue ou ThreePaneScaffoldState séparément. Cette flexibilité vous permet d'implémenter une logique personnalisée pour l'espacement des volets et de déterminer le nombre de volets à afficher simultanément. Vous pouvez également activer la prévisualisation du Retour en ajoutant ThreePaneScaffoldPredictiveBackHandler.

Ajouter ThreePaneScaffoldPredictiveBackHandler

Associez le gestionnaire de prévisualisation du Retour qui prend une instance de navigateur Scaffold et spécifiez le backBehavior. Ce paramètre détermine la manière dont les destinations sont supprimées de la pile "Retour" lors de la navigation vers l'arrière. Transmettez ensuite les scaffoldDirective et scaffoldState à SupportingPaneScaffold. Utilisez la surcharge qui accepte un ThreePaneScaffoldState, en transmettant scaffoldNavigator.scaffoldState.

Définissez les volets principal et secondaire dans SupportingPaneScaffold. Utilisez AnimatedPane pour les animations de volet par défaut.

Une fois ces étapes terminées, votre code doit se présenter comme suit :

val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator()
val scope = rememberCoroutineScope()

ThreePaneScaffoldPredictiveBackHandler(
    navigator = scaffoldNavigator,
    backBehavior = BackNavigationBehavior.PopUntilScaffoldValueChange
)

SupportingPaneScaffold(
    directive = scaffoldNavigator.scaffoldDirective,
    scaffoldState = scaffoldNavigator.scaffoldState,
    mainPane = {
        MainPane(
            shouldShowSupportingPaneButton = scaffoldNavigator.scaffoldValue.secondary == PaneAdaptedValue.Hidden,
            onNavigateToSupportingPane = {
                scope.launch {
                    scaffoldNavigator.navigateTo(ThreePaneScaffoldRole.Secondary)
                }
            }
        )
    },
    supportingPane = { SupportingPane() },
)