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. 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 para 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 un panel 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.
Cómo declarar dependencias
ListDetailPaneScaffold
es parte de la biblioteca adaptable de Material 3.
Agrega una dependencia para la biblioteca en el archivo build.gradle
de tu app o módulo:
implementation("androidx.compose.material3.adaptive:adaptive:1.0.0-alpha07")
implementation("androidx.compose.material3.adaptive:adaptive-layout:1.0.0-alpha07")
implementation("androidx.compose.material3.adaptive:adaptive-navigation:1.0.0-alpha07")
Uso básico
A continuación, se muestra el uso básico de ListDetailPaneScaffold
:
Almacena el elemento seleccionado actualmente de la lista en una variable de estado mutable. La variable contiene el elemento que se mostrará en el panel de detalles. Por lo general, es recomendable inicializar el elemento seleccionado actualmente con
null
, lo que indica que aún no se realizó ninguna selección.class MyItem(val id: Int) { companion object { val Saver: Saver<MyItem?, Int> = Saver( { it?.id }, ::MyItem, ) } }
var selectedItem: MyItem? by rememberSaveable(stateSaver = MyItem.Saver) { mutableStateOf(null) }
Crea el
ThreePaneScaffoldNavigator
conrememberListDetailPaneScaffoldNavigator
y agrega unBackHandler
. Este navegador se usa para moverse entre la lista, los detalles y los paneles adicionales, y proporcionar el estado al andamiaje. El elementoBackHandler
agregado admite la navegación hacia atrás con el botón o el gesto atrás del sistema. El comportamiento esperado del botón Atrás para un objetoListDetailPaneScaffold
depende del tamaño de la ventana y del valor actual del andamiaje. SiListDetailPaneScaffold
admite la recuperación con el estado actual,canNavigateBack()
serátrue
, lo que habilitaráBackHandler
.val navigator = rememberListDetailPaneScaffoldNavigator<Nothing>() BackHandler(navigator.canNavigateBack()) { navigator.navigateBack() }
Pasa el
scaffoldState
de lanavigator
que creaste al elementoListDetailPaneScaffold
componible.ListDetailPaneScaffold( directive = navigator.scaffoldDirective, value = navigator.scaffoldValue, // ... )
Proporciona la implementación del panel de lista a
ListDetailPaneScaffold
. Asegúrate de que tu implementación incluya un argumento de devolución de llamada para capturar el elemento recién seleccionado. Cuando se active esta devolución de llamada, actualiza la variable de estadoselectedItem
y usaThreePaneScaffoldNavigator
para mostrar el panel de detalles (ListDetailPaneScaffoldRole.Detail
).ListDetailPaneScaffold( directive = navigator.scaffoldDirective, value = navigator.scaffoldValue, listPane = { AnimatedPane(Modifier) { MyList( onItemClick = { id -> // Set current item selectedItem = id // Switch focus to detail pane navigator.navigateTo(ListDetailPaneScaffoldRole.Detail) } ) } }, // ... )
Incluye la implementación del panel de detalles en
ListDetailPaneScaffold
. Muestra el contenido de los detalles solo si elselectedItem
no es nulo.ListDetailPaneScaffold( directive = navigator.scaffoldDirective, value = navigator.scaffoldValue, listPane = // ... detailPane = { AnimatedPane(Modifier) { selectedItem?.let { item -> MyDetails(item) } } }, )
Después de implementar los pasos anteriores, tu código debería ser similar al siguiente:
// Currently selected item var selectedItem: MyItem? by rememberSaveable(stateSaver = MyItem.Saver) { mutableStateOf(null) } // Create the ListDetailPaneScaffoldState val navigator = rememberListDetailPaneScaffoldNavigator<Nothing>() BackHandler(navigator.canNavigateBack()) { navigator.navigateBack() } ListDetailPaneScaffold( directive = navigator.scaffoldDirective, value = navigator.scaffoldValue, listPane = { AnimatedPane(Modifier) { MyList( onItemClick = { id -> // Set current item selectedItem = id // Display the detail pane navigator.navigateTo(ListDetailPaneScaffoldRole.Detail) }, ) } }, detailPane = { AnimatedPane(Modifier) { // Show the detail pane content if selected item is available selectedItem?.let { item -> MyDetails(item) } } }, )