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 grandes colecciones, 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. El uso de lista-detalles también se puede usar para rutas menos críticas, como dividir las preferencias de una app en una lista de categorías con las preferencias de cada categoría en el panel de detalles.

Implementa el patrón de 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 uno adicional opcional. El andamiaje controla los cálculos del espacio de pantalla. Cuando hay un tamaño de pantalla suficiente, se muestra el panel de detalles junto al panel de lista. En tamaños de pantalla pequeños, el andamiaje cambia automáticamente a mostrar la lista o el panel de detalles en pantalla completa.

Se muestra un panel de detalles junto a la página de lista.
Figura 1: Cuando haya suficiente tamaño de pantalla disponible, se mostrará 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 (desde 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 relacionadas de Material 3:

  • Adaptable: Componentes básicos de bajo nivel, como HingeInfo y Posture
  • Diseño adaptable: Diseños adaptables, como ListDetailPaneScaffold y SupportingPaneScaffold
    • adaptive-navigation: Elementos componibles para navegar dentro 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 admitir el guardado y el restablecimiento del elemento de lista seleccionado. Usa el complemento de kotlin-parcelize para generar el código por ti.

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

  2. Crea un ThreePaneScaffoldNavigator con rememberListDetailPaneScaffoldNavigator y agrega un BackHandler. Este navegador se usa para desplazarse entre la lista, los paneles de detalles y los paneles adicionales. Cuando se declara un tipo genérico, el navegador también hace 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 en la configuración. El objeto BackHandler proporciona compatibilidad para navegar hacia atrás con el botón o gesto de retroceso del sistema. El comportamiento esperado del botón Atrás para un objeto ListDetailPaneScaffold depende del tamaño de la ventana y del valor actual del andamiaje. Si ListDetailPaneScaffold puede admitir la opción de 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 de navigator al elemento ListDetailPaneScaffold componible.

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

  4. Proporciona la implementación del panel de lista a ListDetailPaneScaffold. Usa AnimatedPane para aplicar las animaciones de paneles 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 complete la navegación, currentDestination contendrá el panel al que navegó tu app, incluido el contenido que se muestra en él. La propiedad content es el mismo tipo especificado en la llamada original de recuerdos (en este ejemplo, MyItem), por lo que también puedes acceder a ella 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)
            }
        }
    },
)