Lista-detalles es un patrón de IU que consiste en un diseño de dos paneles, en el que uno presenta una lista de elementos y el otro muestra los detalles de los elementos seleccionados de la lista.
El patrón es especialmente útil para las aplicaciones que proporcionan información detallada sobre los elementos de colecciones grandes, por ejemplo, un cliente de correo electrónico que tiene una lista de correos electrónicos y el contenido detallado de cada mensaje de correo electrónico. La lista-detalles también se puede usar para rutas de acceso menos críticas, como dividir las preferencias de la app en una lista de categorías con las preferencias de cada categoría en el panel de detalles.

Implementa el patrón de lista-detalles con NavigableListDetailPaneScaffold
NavigableListDetailPaneScaffold es un elemento componible que simplifica la implementación de un diseño de lista-detalles en Jetpack Compose. Une ListDetailPaneScaffold y agrega navegación integrada y animaciones de atrás predictivo.
Un scaffold de lista-detalles admite hasta tres paneles:
- Panel de lista: Muestra una colección de elementos.
- Panel de detalles: Muestra los detalles de un elemento seleccionado.
- Panel adicional (opcional): Proporciona contexto adicional cuando es necesario.
El scaffold se adapta según el tamaño de la ventana:
- En las ventanas grandes, los paneles de lista y detalles aparecen uno al lado del otro.
- En las ventanas pequeñas, solo se puede ver un panel a la vez, que cambia a medida que los usuarios navegan.
Cómo declarar dependencias
NavigableListDetailPaneScaffold forma parte de la biblioteca de navegación 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'
- adaptable: Componentes básicos de bajo nivel, como
HingeInfoyPosture - adaptive-layout: Diseños adaptables, como
ListDetailPaneScaffoldySupportingPaneScaffold - adaptive-navigation: Son funciones de componibilidad para navegar dentro de los paneles y entre ellos, así como diseños adaptables que admiten la navegación de forma predeterminada, como
NavigableListDetailPaneScaffoldyNavigableSupportingPaneScaffold.
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 habilitar la compatibilidad con el gesto atrás predictivo. Para habilitarla, agrega
android:enableOnBackInvokedCallback="true" a la etiqueta <application> o
a las etiquetas <activity> individuales dentro del archivo AndroidManifest.xml. Para obtener más información, consulta Cómo habilitar el gesto atrás predictivo.
Una vez que tu app se oriente a Android 16 (nivel de API 36) o versiones posteriores, el gesto atrás predictivo estará habilitado de forma predeterminada.
Uso básico
Implementa NavigableListDetailPaneScaffold de la siguiente manera:
- Usa una clase que represente el contenido seleccionado. Usa una clase
Parcelablepara admitir el guardado y el restablecimiento del elemento de lista seleccionado. Usa el complemento kotlin-parcelize para generar el código por ti. - Crea un
ThreePaneScaffoldNavigatorconrememberListDetailPaneScaffoldNavigator.
Este navegador se usa para moverse entre los paneles de lista, detalles y adicionales. Cuando declaras un tipo genérico, el navegador también hace un seguimiento del estado del scaffold (es decir, qué MyItem se muestra). Como este tipo es parcelable, el navegador puede guardar y restablecer el estado para controlar automáticamente los cambios de configuración.
Pasa el navegador al elemento componible
NavigableListDetailPaneScaffold.Proporciona tu implementación del panel de lista a
NavigableListDetailPaneScaffold. UsaAnimatedPanepara aplicar las animaciones de panel predeterminadas durante la navegación. Luego, usaThreePaneScaffoldNavigatorpara navegar al panel de detalles,ListDetailPaneScaffoldRole.Detail, y mostrar el elemento pasado.Incluye la implementación del panel de detalles en
NavigableListDetailPaneScaffold.
Cuando se completa la navegación, currentDestination contiene el panel al que navegó tu app, incluido el contenido que se muestra en el panel. La propiedad contentKey es del mismo tipo que se especificó en la llamada original, por lo que puedes acceder a cualquier dato que necesites mostrar.
- De manera opcional, cambia el
defaultBackBehaviorenNavigableListDetailPaneScaffold. De forma predeterminada,NavigableListDetailPaneScaffoldusaPopUntilScaffoldValueChangeparadefaultBackBehavior.
Si tu app requiere un patrón de navegación hacia atrás diferente, puedes anular este comportamiento especificando otra opción de BackNavigationBehavior.
Opciones de BackNavigationBehavior
En la siguiente sección, se usa el ejemplo de una app de correo electrónico con una lista de correos electrónicos en un panel y una vista detallada en el otro.
PopUntilScaffoldValueChange (predeterminado y recomendado en la mayoría de los casos)
Este comportamiento se enfoca en los cambios en la estructura general del diseño. En una configuración de varios paneles, cambiar el contenido del correo electrónico en el panel de detalles no altera la estructura de diseño subyacente. Por lo tanto, el botón Atrás podría salir de la app o del gráfico de navegación actual, ya que no hay ningún cambio de diseño al que se pueda volver dentro del contexto actual. En un diseño de un solo panel, presionar Atrás omitirá los cambios de contenido dentro de la vista de detalles y volverá a la vista de lista, ya que esto representa un cambio de diseño claro.
Considera los siguientes ejemplos:
- Panel múltiple: Estás viendo un correo electrónico (elemento 1) en el panel de detalles. Si haces clic en otro correo electrónico (elemento 2), se actualiza el panel de detalles, pero los paneles de lista y de detalles permanecen visibles. Si presionas Atrás, es posible que salgas de la app o del flujo de navegación actual.
- Panel único: Si ves el elemento 1 y, luego, el elemento 2, cuando presiones Atrás, volverás directamente al panel de la lista de correos electrónicos.
Usa esta opción cuando quieras que los usuarios perciban transiciones de diseño distintas con cada acción de retroceso.
PopUntilContentChange
Este comportamiento prioriza el contenido que se muestra. Si ves el elemento 1 y, luego, el elemento 2, cuando presiones Atrás, volverás al elemento 1, independientemente del diseño.
Considera los siguientes ejemplos:
- Panel múltiple: Ves el elemento 1 en el panel de detalles y, luego, haces clic en el elemento 2 en la lista. Se actualizará el panel de detalles. Si presionas Atrás, se restablecerá el panel de detalles al elemento 1.
- Panel único: Se produce la misma reversión de contenido.
Usa esta opción cuando el usuario espere volver al contenido visto anteriormente con la acción Atrás.
PopUntilCurrentDestinationChange
Este comportamiento quita la pila de actividades hasta que cambia el destino de navegación actual. Esto se aplica de igual manera a los diseños de un solo panel y de varios paneles.
Considera los siguientes ejemplos:
Independientemente de si estás en un diseño de un solo panel o de varios, presionar Atrás siempre moverá el enfoque del elemento de navegación destacado al destino anterior. En nuestra app de correo electrónico, esto significa que cambiará la indicación visual del panel seleccionado.
Usa esta opción cuando mantener una indicación visual clara de la navegación actual sea fundamental para la experiencia del usuario.
PopLatest
Esta opción solo quita el destino más reciente de la pila de actividades. Usa esta opción para la navegación hacia atrás sin omitir estados intermedios.
Después de implementar estos pasos, tu código debería ser similar al siguiente:
NavigableListDetailPaneScaffold( navigator = navigator, listPane = { AnimatedPane { ListContent( words = sampleWords, selectionState = navigator.currentDestination?.contentKey?.let { SelectionVisibilityState.ShowSelection(it) } ?: SelectionVisibilityState.NoSelection, onWordClick = { word -> scope.launch { navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, word) } }, animatedVisibilityScope = this@AnimatedPane, sharedTransitionScope = this@SharedTransitionLayout ) } }, detailPane = { AnimatedPane { DetailContent( definedWord = navigator.currentDestination?.contentKey, animatedVisibilityScope = this@AnimatedPane, sharedTransitionScope = this@SharedTransitionLayout, onClosePane = { scope.launch { navigator.navigateBack( backNavigationBehavior = BackNavigationBehavior.PopUntilScaffoldValueChange ) } } ) } }