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

Lista-detalles es un patrón de IU que consiste en un diseño de panel doble, 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 aplicaciones que proporcionan información detallada sobre elementos de colecciones grandes, como un cliente de correo electrónico que tiene una lista de correos electrónicos y el contenido detallado de cada mensaje. 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 preferencias para cada categoría en el panel de detalles.

Implementa el patrón de la IU con ListDetailPaneScaffold

ListDetailPaneScaffold es un elemento componible que simplifica la implementación del patrón de lista-detalles en tu app. Un andamiaje de lista-detalles puede constar de hasta tres paneles: uno de lista, uno de detalles y un panel adicional opcional. El andamiaje se encarga de los cálculos del espacio de pantalla. Cuando hay suficiente tamaño de pantalla disponible, el panel de detalles se muestra junto al panel de lista. En pantallas de tamaño pequeño, el andamiaje cambia automáticamente a la pantalla completa del panel de detalles o de la lista.

Un panel de detalles que se muestra junto a la página de lista.
Figura 1: Cuando hay suficiente tamaño de pantalla disponible, se muestra el panel de detalles junto al 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.

Cómo declarar dependencias

ListDetailPaneScaffold es parte de la biblioteca de diseño adaptable de Material 3.

Tu app debe incluir dependencias para tres bibliotecas de Material 3 relacionadas:

  • Adaptable: Componentes básicos de bajo nivel, como HingeInfo y Posture
  • Diseño adaptable: Diseños adaptables, como ListDetailPaneScaffold y SupportingPaneScaffold
    • adaptive-navigation: Elementos que admiten composición para navegar dentro de paneles y entre paneles

Agrega las dependencias al archivo build.gradle de tu app o módulo:

Kotlin


implementation("androidx.compose.material3.adaptive:adaptive:1.0.0-alpha12")
implementation("androidx.compose.material3.adaptive:adaptive-layout:1.0.0-alpha12")
implementation("androidx.compose.material3.adaptive:adaptive-navigation:1.0.0-alpha12")

Groovy


implementation 'androidx.compose.material3.adaptive:adaptive:1.0.0-alpha12'
implementation 'androidx.compose.material3.adaptive:adaptive-layout:1.0.0-alpha12'
implementation 'androidx.compose.material3.adaptive:adaptive-navigation:1.0.0-alpha12'

Uso básico

Implementa ListDetailPaneScaffold de la siguiente manera:

  1. Usa una clase que represente el contenido que se seleccionará. Esta clase debe ser Parcelable para poder guardar y restablecer el elemento de lista seleccionado. Usa el complemento kotlin-parcelize para generar el código.

    @Parcelize
    class MyItem(val id: Int) : Parcelable

  2. Crea un ThreePaneScaffoldNavigator con rememberListDetailPaneScaffoldNavigator y agrega un BackHandler. Este navegador se usa para moverse entre los paneles de lista, de detalles y adicionales. Cuando declaras un tipo genérico, el navegador también realiza un seguimiento del estado del andamiaje (es decir, qué MyItem se muestra). Dado que este tipo es parcelable, el navegador puede guardar y restablecer el estado para controlar automáticamente los cambios de configuración. BackHandler proporciona compatibilidad para navegar hacia atrás con el gesto o botón atrás del sistema. El comportamiento esperado del botón Atrás para una ListDetailPaneScaffold depende del tamaño de la ventana y del valor de andamiaje actual. Si ListDetailPaneScaffold puede admitir volver con el estado actual, canNavigateBack() es true, lo que habilita BackHandler.

    val navigator = rememberListDetailPaneScaffoldNavigator<MyItem>()
    
    BackHandler(navigator.canNavigateBack()) {
        navigator.navigateBack()
    }

  3. Pasa el scaffoldState del navigator al elemento ListDetailPaneScaffold componible.

    ListDetailPaneScaffold(
        directive = navigator.scaffoldDirective,
        value = navigator.scaffoldValue,
        // ...
    )

  4. Proporciona tu implementación del panel de lista a ListDetailPaneScaffold. 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 muestra el elemento que se pasó.

    ListDetailPaneScaffold(
        directive = navigator.scaffoldDirective,
        value = navigator.scaffoldValue,
        listPane = {
            AnimatedPane {
                MyList(
                    onItemClick = { item ->
                        // Navigate to the detail pane with the passed item
                        navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, item)
                    }
                )
            }
        },
        // ...
    )

  5. Incluye la implementación del panel de detalles en ListDetailPaneScaffold. 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 content es del mismo tipo especificado en la llamada de recordatorio original (MyItem en este ejemplo), por lo que también puedes acceder a la propiedad para cualquier dato que necesites mostrar.

    ListDetailPaneScaffold(
        directive = navigator.scaffoldDirective,
        value = navigator.scaffoldValue,
        listPane =
        // ...
        detailPane = {
            AnimatedPane {
                navigator.currentDestination?.content?.let {
                    MyDetails(it)
                }
            }
        },
    )

Después de implementar los pasos anteriores, tu código debería ser similar al siguiente:

val navigator = rememberListDetailPaneScaffoldNavigator<MyItem>()

BackHandler(navigator.canNavigateBack()) {
    navigator.navigateBack()
}

ListDetailPaneScaffold(
    directive = navigator.scaffoldDirective,
    value = navigator.scaffoldValue,
    listPane = {
        AnimatedPane {
            MyList(
                onItemClick = { item ->
                    // Navigate to the detail pane with the passed item
                    navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, item)
                },
            )
        }
    },
    detailPane = {
        AnimatedPane {
            // Show the detail pane content if selected item is available
            navigator.currentDestination?.content?.let {
                MyDetails(it)
            }
        }
    },
)