Cómo compilar un diseño de detalles de lista

La lista-detalles es un patrón de IU que consiste en un diseño de dos paneles, en el que un panel presenta una lista de elementos y otro muestra los detalles de los elementos seleccionados de la lista.

El patrón es particularmente útil para las aplicaciones que proporcionan información detallada sobre 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. La lista de detalles también se puede usar para rutas menos importantes, 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.

Un panel de detalles que se muestra junto a la página de la lista.
Figura 1: Cuando hay suficiente tamaño de pantalla disponible, el panel de detalles se muestra junto con el panel de lista.
Después de seleccionar un elemento, el panel de detalles ocupa toda la pantalla.
Figura 2: Cuando el tamaño de la pantalla es limitado, el panel de detalles (ya que se seleccionó un elemento) ocupa todo el espacio.

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 animaciones de atrás predictivo y navegación integradas.

Un andamiaje de lista-detalles admite hasta tres paneles:

  1. Panel de lista: Muestra una colección de elementos.
  2. Panel de detalles: Muestra los detalles de un elemento seleccionado.
  3. Panel adicional (opcional): Proporciona contexto adicional cuando sea necesario.

El andamiaje se adapta según el tamaño de la ventana:

  • En ventanas grandes, los paneles de lista y de detalles 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.

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 HingeInfo y Posture
  • adaptive-layout: Diseños adaptables, como ListDetailPaneScaffold y SupportingPaneScaffold
  • 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 y NavigableSupportingPaneScaffold

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 a etiquetas <activity> individuales dentro de tu archivo AndroidManifest.xml. Para obtener más información, consulta Cómo aceptar el gesto atrás predictivo.

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.

Uso básico

Implementa NavigableListDetailPaneScaffold de la siguiente manera:

  1. Usa una clase que represente el contenido seleccionado. Usa una clase Parcelable para admitir el guardado y el restablecimiento del elemento de lista seleccionado. Usa el complemento kotlin-parcelize para que genere el código por ti.
  2. Crea un ThreePaneScaffoldNavigator con rememberListDetailPaneScaffoldNavigator.

Este navegador se usa para moverse entre la lista, los paneles de detalles y los adicionales. Cuando se declara un tipo genérico, el navegador también realiza un seguimiento del estado del andamiaje (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.

  1. Pasa el navegador al elemento NavigableListDetailPaneScaffold componible.

  2. Proporciona la implementación del panel de listas a NavigableListDetailPaneScaffold. Usa AnimatedPane para aplicar las animaciones de panel predeterminadas durante la navegación. Luego, usa ThreePaneScaffoldNavigator para navegar al panel de detalles, ListDetailPaneScaffoldRole.Detail, y mostrar el elemento pasado.

  3. 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 él. La propiedad contentKey es del mismo tipo que se especifica en la llamada original, por lo que puedes acceder a cualquier dato que necesites mostrar.

  1. De manera opcional, cambia el defaultBackBehavior en NavigableListDetailPaneScaffold. De forma predeterminada, NavigableListDetailPaneScaffold usa PopUntilScaffoldValueChange para defaultBackBehavior.

Si tu app requiere un patrón de navegación hacia atrás diferente, puedes anular este comportamiento especificando otra opción de BackNavigationBehavior.

BackNavigationBehavior opciones

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.

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, es posible que el botón Atrás salga de la app o del gráfico de navegación actual porque no hay un cambio de diseño al que volver dentro del contexto actual. En un diseño de un solo panel, presionar Atrás omitirá los cambios de contenido en 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:

  • Varios paneles: 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 actualizará el panel de detalles, pero los paneles de lista y de detalles permanecerán visibles. Si presionas Atrás, es posible que salgas de la app o del flujo de navegación actual.
  • Un solo panel: Ves el elemento 1 y, luego, el elemento 2. Si presionas Atrás, regresarás directamente al panel de la lista de correos electrónicos.

Úsalo cuando quieras que los usuarios perciban transiciones de diseño distintas con cada acción de atrás.

Cambio de valor de navegación
PopUntilContentChange

Este comportamiento prioriza el contenido que se muestra. Si ves el elemento 1 y, luego, el elemento 2, si presionas Atrás, se volverá al elemento 1, independientemente del diseño.

Considera los siguientes ejemplos:

  • Paneles múltiples: Consultas el elemento 1 en el panel de detalles y, luego, haces clic en el elemento 2 de la lista. Se actualizará el panel de detalles. Si presionas Atrás, se restablecerá el panel de detalles al elemento 1.
  • Un solo panel: Se produce la misma reversión de contenido.

Úsalo cuando el usuario espere volver al contenido que vio anteriormente con la acción Atrás.

la transición entre dos paneles de detalles
PopUntilCurrentDestinationChange

Este comportamiento muestra la pila de actividades hasta que cambia el destino de navegación actual. Esto se aplica de la misma 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 paneles, 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 la indicación visual del panel seleccionado cambiará.

Úsalo cuando sea fundamental para la experiencia del usuario mantener una indicación visual clara de la navegación actual.

navegar entre los paneles de lista y de detalles
PopLatest

Esta opción quita solo 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:

val scaffoldNavigator = rememberListDetailPaneScaffoldNavigator<MyItem>()
val scope = rememberCoroutineScope()

NavigableListDetailPaneScaffold(
    navigator = scaffoldNavigator,
    listPane = {
        AnimatedPane {
            MyList(
                onItemClick = { item ->
                    // Navigate to the detail pane with the passed item
                    scope.launch {
                        scaffoldNavigator.navigateTo(
                            ListDetailPaneScaffoldRole.Detail,
                            item
                        )
                    }
                },
            )
        }
    },
    detailPane = {
        AnimatedPane {
            // Show the detail pane content if selected item is available
            scaffoldNavigator.currentDestination?.contentKey?.let {
                MyDetails(it)
            }
        }
    },
)