El diseño de panel complementario mantiene el enfoque del usuario en el contenido principal de la app mientras muestra información complementaria pertinente. Por ejemplo, el panel principal puede mostrar detalles sobre una película, mientras que el panel secundario enumera películas similares, películas del mismo director o trabajos con los mismos actores.
Para obtener más detalles, consulta los lineamientos del panel secundario de Material 3.
Implementa un panel complementario con un scaffold
NavigableSupportingPaneScaffold
es un elemento componible que simplifica la implementación de un diseño de panel secundario en Jetpack Compose. Encapsula SupportingPaneScaffold
y agrega navegación integrada y control del gesto atrás predictivo.
Un andamio de panel complementario admite hasta tres paneles:
- Panel principal: Muestra el contenido principal.
- Panel complementario: Proporciona contexto o herramientas adicionales relacionados con el panel principal.
- Panel adicional (opcional): Se usa para contenido complementario cuando es necesario.
El andamio se adapta según el tamaño de la ventana:
- En ventanas grandes, los paneles principal y complementario aparecen uno al lado del otro.
En ventanas pequeñas, solo se ve un panel a la vez, que cambia a medida que los usuarios navegan.
Figura 1. Diseño del panel complementario.
Cómo agregar dependencias
NavigableSupportingPaneScaffold
forma parte de la biblioteca de diseño adaptable de Material 3.
Agrega las siguientes tres dependencias relacionadas al archivo build.gradle
de tu app o módulo:
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'
Adaptables: Componentes básicos de bajo nivel, como
HingeInfo
yPosture
adaptive-layout: Diseños adaptables, como
ListDetailPaneScaffold
ySupportingPaneScaffold
adaptive-navigation: Elementos componibles para navegar dentro de paneles y entre ellos, así como diseños adaptables que admiten la navegación de forma predeterminada, como
NavigableListDetailPaneScaffold
yNavigableSupportingPaneScaffold
Asegúrate de que tu proyecto incluya compose-material3-adaptive versión 1.1.0-beta1 o posterior.
Acepta el gesto atrás predictivo
Para habilitar las animaciones de atrás predictivo en Android 15 o versiones anteriores, debes habilitar la compatibilidad con el gesto atrás predictivo. Para habilitar el estilo, agrega android:enableOnBackInvokedCallback="true"
a la etiqueta <application>
o a las etiquetas <activity>
individuales dentro de tu archivo AndroidManifest.xml
.
Una vez que tu app se segmenta para Android 16 (nivel de API 36) o versiones posteriores, el gesto de atrás predictivo se habilita de forma predeterminada.
Cómo crear un navegador
En ventanas pequeñas, solo se muestra un panel a la vez, por lo que debes usar ThreePaneScaffoldNavigator
para ir de un panel a otro. Crea una instancia del navegador con rememberSupportingPaneScaffoldNavigator
.
val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator() val scope = rememberCoroutineScope()
Pasa el navegador al andamio
El andamio requiere un ThreePaneScaffoldNavigator
, que es una interfaz que representa el estado del andamio, el ThreePaneScaffoldValue
y un PaneScaffoldDirective
.
NavigableSupportingPaneScaffold( navigator = scaffoldNavigator, mainPane = { /*...*/ }, supportingPane = { /*...*/ }, )
El panel principal y el panel complementario son elementos componibles que contienen tu contenido. Usa AnimatedPane
para aplicar las animaciones predeterminadas del panel durante la navegación. Usa el valor de andamio para verificar si el panel de asistencia está oculto. Si es así, muestra un botón que llame a navigateTo(SupportingPaneScaffoldRole.Supporting)
para mostrar el panel de asistencia.
A continuación, se muestra una implementación completa del andamio:
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") } } )
Cómo extraer elementos componibles del panel
Extrae los paneles individuales de un SupportingPaneScaffold
en sus propios elementos componibles para que sean reutilizables y se puedan probar. Usa ThreePaneScaffoldScope
para acceder a AnimatedPane
si deseas las animaciones predeterminadas:
@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") } }
Extraer los paneles en elementos componibles simplifica el uso de SupportingPaneScaffold
(compara lo siguiente con la implementación completa del diseño en la sección anterior):
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 necesitas más control sobre aspectos específicos del andamio, considera usar SupportingPaneScaffold
en lugar de NavigableSupportingPaneScaffold
. Esto acepta un PaneScaffoldDirective
y un ThreePaneScaffoldValue
o un ThreePaneScaffoldState
por separado. Esta flexibilidad te permite implementar lógica personalizada para el espaciado de los paneles y determinar cuántos paneles se deben mostrar de forma simultánea. También puedes agregar ThreePaneScaffoldPredictiveBackHandler
para habilitar la compatibilidad con el gesto atrás predictivo.
Se agregó ThreePaneScaffoldPredictiveBackHandler
.
Adjunta el controlador de atrás predictivo que toma una instancia del navegador de andamios y especifica el backBehavior
. Esto determina cómo se quitan los destinos de la pila de actividades durante la navegación hacia atrás. Luego, pasa scaffoldDirective
y scaffoldState
a SupportingPaneScaffold
. Usa la sobrecarga que acepta un ThreePaneScaffoldState
y pasa scaffoldNavigator.scaffoldState
.
Define los paneles principal y de asistencia dentro de SupportingPaneScaffold
. Usa AnimatedPane
para las animaciones del panel predeterminado.
Después de implementar estos pasos, tu código debería ser similar al siguiente:
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() }, )