Cómo migrar CoordinatorLayout a Compose

CoordinatorLayout es un ViewGroup que habilita funciones complejas, superpuestas y diseños anidados. Se usa como contenedor para habilitar recursos específicos de Material Design como las hojas inferiores y las barras de herramientas de expansión o contracción, para los objetos View que contiene.

En Compose, el equivalente más cercano a CoordinatorLayout es un Scaffold Un Scaffold proporciona espacios de contenido para combinar Material. Componentes en patrones de pantalla e interacciones comunes. En esta página, se describe cómo puedes migrar tu implementación de CoordinatorLayout para usar Scaffold en Compose

Pasos de la migración

Para migrar CoordinatorLayout a Scaffold, sigue estos pasos:

  1. En el siguiente fragmento, CoordinatorLayout contiene un AppBarLayout para que contiene un ToolBar, un ViewPager y un FloatingActionButton. Comentar la CoordinatorLayout y sus elementos secundarios desde la jerarquía de tu IU y agrega un ComposeView para reemplazarlo.

    <!--  <androidx.coordinatorlayout.widget.CoordinatorLayout-->
    <!--      android:id="@+id/coordinator_layout"-->
    <!--      android:layout_width="match_parent"-->
    <!--      android:layout_height="match_parent"-->
    <!--      android:fitsSystemWindows="true">-->
    
    <!--    <androidx.compose.ui.platform.ComposeView-->
    <!--        android:id="@+id/compose_view"-->
    <!--        android:layout_width="match_parent"-->
    <!--        android:layout_height="match_parent"-->
    <!--        app:layout_behavior="@string/appbar_scrolling_view_behavior" />-->
    
    <!--    <com.google.android.material.appbar.AppBarLayout-->
    <!--        android:id="@+id/app_bar_layout"-->
    <!--        android:layout_width="match_parent"-->
    <!--        android:layout_height="wrap_content"-->
    <!--        android:fitsSystemWindows="true"-->
    <!--        android:theme="@style/Theme.Sunflower.AppBarOverlay">-->
    
        <!-- AppBarLayout contents here -->
    
    <!--    </com.google.android.material.appbar.AppBarLayout>-->
    
    <!--  </androidx.coordinatorlayout.widget.CoordinatorLayout>-->
    
    <androidx.compose.ui.platform.ComposeView
        android:id="@+id/compose_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    
  2. En tu fragmento o actividad, obtén una referencia al ComposeView que que acabas de agregar y llama al método setContent. En el cuerpo del método, establece un Scaffold como su contenido:

    composeView.setContent {
        Scaffold(Modifier.fillMaxSize()) { contentPadding ->
            // Scaffold contents
            // ...
        }
    }

  3. En el contenido de tu Scaffold, agrega el contenido principal de tu pantalla dentro que la modifica. Como el contenido principal del XML anterior es un ViewPager2, usaremos un HorizontalPager, que es su equivalente en Compose La lambda content de Scaffold también recibe una instancia de PaddingValues que debería a la raíz del contenido. Puedes usar Modifier.padding para aplicar el mismo PaddingValues a HorizontalPager.

    composeView.setContent {
        Scaffold(Modifier.fillMaxSize()) { contentPadding ->
            val pagerState = rememberPagerState {
                10
            }
            HorizontalPager(
                state = pagerState,
                modifier = Modifier.padding(contentPadding)
            ) { /* Page contents */ }
        }
    }

  4. Usa otros espacios de contenido que proporciona Scaffold para agregar más elementos de pantalla. y migrar las vistas secundarias restantes. Puedes usar el espacio topBar para agregar una TopAppBar y el espacio floatingActionButton para proporcionar un FloatingActionButton.

    composeView.setContent {
        Scaffold(
            Modifier.fillMaxSize(),
            topBar = {
                TopAppBar(
                    title = {
                        Text("My App")
                    }
                )
            },
            floatingActionButton = {
                FloatingActionButton(
                    onClick = { /* Handle click */ }
                ) {
                    Icon(
                        Icons.Filled.Add,
                        contentDescription = "Add Button"
                    )
                }
            }
        ) { contentPadding ->
            val pagerState = rememberPagerState {
                10
            }
            HorizontalPager(
                state = pagerState,
                modifier = Modifier.padding(contentPadding)
            ) { /* Page contents */ }
        }
    }

Casos de uso comunes

Contraer y expandir barras de herramientas

En el sistema de View, para contraer y expandir la barra de herramientas con CoordinatorLayout, haz lo siguiente: usa un AppBarLayout como contenedor de la barra de herramientas. Luego, puedes especificar De Behavior a layout_behavior en XML en el elemento desplazable asociado (como RecyclerView o NestedScrollView) para declarar cómo se muestra se contrae o se expande a medida que te desplazas.

En Compose, puedes lograr un efecto similar con un TopAppBarScrollBehavior Por ejemplo, para implementar una interfaz de contracción o expansión barra de herramientas de modo que aparezca cuando te desplaces hacia arriba, sigue estos pasos:

  1. Llama a TopAppBarDefaults.enterAlwaysScrollBehavior() para crear un TopAppBarScrollBehavior
  2. Proporciona el TopAppBarScrollBehavior creado a TopAppBar.
  3. Conecta el NestedScrollConnection a través de Modifier.nestedScroll en el Scaffold para que Scaffold pueda recibir eventos de desplazamiento anidados como el elemento el contenido desplazable se desplaza hacia arriba o hacia abajo. De esta manera, la barra de la app contenida se contraen o expanden de manera adecuada a medida que se desplaza el contenido.

    // 1. Create the TopAppBarScrollBehavior
    val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
    
    Scaffold(
        topBar = {
            TopAppBar(
                title = {
                    Text("My App")
                },
                // 2. Provide scrollBehavior to TopAppBar
                scrollBehavior = scrollBehavior
            )
        },
        // 3. Connect the scrollBehavior.nestedScrollConnection to the Scaffold
        modifier = Modifier
            .fillMaxSize()
            .nestedScroll(scrollBehavior.nestedScrollConnection)
    ) { contentPadding ->
        /* Contents */
        // ...
    }

Cómo personalizar el efecto de desplazamiento que se contrae o se expande

Puedes proporcionar varios parámetros para enterAlwaysScrollBehavior para lo siguiente: Personalizar el efecto de la animación que se contrae/expande. TopAppBarDefaults también proporciona otros TopAppBarScrollBehavior, como exitUntilCollapsedScrollBehavior, que solo expande la barra de la app cuando el contenido se desplaza hasta el final.

Para crear un efecto completamente personalizado (por ejemplo, un efecto de paralaje), puedes También puedes crear tu propio NestedScrollConnection y desplazar la barra de herramientas manualmente como se desplaza el contenido. Consulta el ejemplo de desplazamiento anidado en AOSP para obtener un ejemplo de código.

Paneles laterales

Con Views, implementas un panel lateral de navegación con un DrawerLayout como vista raíz. A su vez, tu CoordinatorLayout es un vista secundaria de DrawerLayout. La DrawerLayout también contiene otro elemento secundario como NavigationView, para mostrar las opciones de navegación en el panel lateral.

En Compose, puedes implementar un panel lateral de navegación con el elemento Elemento ModalNavigationDrawer componible. ModalNavigationDrawer ofrece un Ranura drawerContent para el panel lateral y una ranura content para la pantalla contenido.

ModalNavigationDrawer(
    drawerContent = {
        ModalDrawerSheet {
            Text("Drawer title", modifier = Modifier.padding(16.dp))
            Divider()
            NavigationDrawerItem(
                label = { Text(text = "Drawer Item") },
                selected = false,
                onClick = { /*TODO*/ }
            )
            // ...other drawer items
        }
    }
) {
    Scaffold(Modifier.fillMaxSize()) { contentPadding ->
        // Scaffold content
        // ...
    }
}

Consulta Paneles laterales para obtener más información.

Barras de notificaciones

Scaffold proporciona un espacio snackbarHost, que puede aceptar un SnackbarHost. componible para mostrar un Snackbar.

val scope = rememberCoroutineScope()
val snackbarHostState = remember { SnackbarHostState() }
Scaffold(
    snackbarHost = {
        SnackbarHost(hostState = snackbarHostState)
    },
    floatingActionButton = {
        ExtendedFloatingActionButton(
            text = { Text("Show snackbar") },
            icon = { Icon(Icons.Filled.Image, contentDescription = "") },
            onClick = {
                scope.launch {
                    snackbarHostState.showSnackbar("Snackbar")
                }
            }
        )
    }
) { contentPadding ->
    // Screen content
    // ...
}

Consulta Snackbars para obtener más información.

Más información

Si quieres obtener más información para migrar un objeto CoordinatorLayout a Compose, consulta el siguiente vínculo: los siguientes recursos: