El diseño del panel complementario mantiene la atención del usuario en el contenido principal de la app mientras muestra información complementaria relevante. Por ejemplo, el panel principal podría mostrar detalles sobre una película, mientras que el panel secundario enumera películas similares, del mismo director o con los mismos actores.
Para obtener más detalles, consulta los lineamientos del panel de compatibilidad de Material 3.
Implementa un panel complementario con NavigableSupportingPaneScaffold
NavigableSupportingPaneScaffold
es un elemento componible que simplifica la implementación de un diseño de panel de soporte en Jetpack Compose. Une SupportingPaneScaffold
y agrega navegación integrada y control de atrás predictivo.
Un andamiaje 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 el contenido complementario cuando sea necesario.
El andamiaje 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 puede ver 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'
- adaptativos: Componentes básicos de bajo nivel, como
HingeInfo
yPosture
- adaptive-layout: Diseños adaptables, como
ListDetailPaneScaffold
ySupportingPaneScaffold
- adaptive-navigation: Elementos componibles para navegar dentro y entre paneles, 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 una posterior.
Acepta el gesto atrás predictivo
Para habilitar las animaciones de atrás predictivo en Android 15 o versiones anteriores, debes aceptar el gesto atrás predictivo. Para habilitarlo, agrega android:enableOnBackInvokedCallback="true"
a la etiqueta <application>
[o 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 segmente para Android 16 (nivel de API 36) o versiones posteriores, el gesto atrás predictivo se habilitará de forma predeterminada.
Crea un navegador
En ventanas pequeñas, solo se muestra un panel a la vez, por lo que debes usar un ThreePaneScaffoldNavigator
para moverte entre los paneles. Crea una instancia del navegador con rememberSupportingPaneScaffoldNavigator
.
val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator() val scope = rememberCoroutineScope()
Pasa el navegador al andamiaje
El andamiaje requiere un ThreePaneScaffoldNavigator
, que es una interfaz que representa el estado del andamiaje, 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 de panel predeterminadas durante la navegación. Usa el valor del andamiaje para verificar si el panel de ayuda está oculto. Si es así, muestra un botón que llame a navigateTo(SupportingPaneScaffoldRole.Supporting)
para mostrar el panel de ayuda.
Esta es una implementación completa del andamiaje:
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 testables. Usa ThreePaneScaffoldScope
para acceder a AnimatedPane
si quieres 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 andamiaje 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 andamiaje, considera usar SupportingPaneScaffold
en lugar de NavigableSupportingPaneScaffold
. Acepta PaneScaffoldDirective
y ThreePaneScaffoldValue
o ThreePaneScaffoldState
por separado. Esta flexibilidad te permite implementar una lógica personalizada para el espaciado de paneles y determinar cuántos paneles se deben mostrar de forma simultánea. También puedes habilitar la compatibilidad con el gesto atrás predictivo si agregas ThreePaneScaffoldPredictiveBackHandler
.
Se agregó ThreePaneScaffoldPredictiveBackHandler
.
Adjunta el controlador de atrás predictivo que toma una instancia de navegador de andamiaje 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 secundario dentro de SupportingPaneScaffold
. Usa AnimatedPane
para las animaciones de paneles predeterminadas.
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() }, )