Esegui la migrazione di CoordinatorLayout in Compose

CoordinatorLayout è una ViewGroup che consente layout complessi, che si sovrappongono e nidificati. Viene utilizzato come contenitore per attivare interazioni specifiche di Material Design, come l'espansione/il collasso di barre degli strumenti e riquadri inferiori, per le visualizzazioni al suo interno.

In Componi, l'equivalente più simile di un CoordinatorLayout è un Scaffold. Un Scaffold fornisce slot per i contenuti per combinare i componenti Materiale in pattern e interazioni comuni con le schermate. Questa pagina descrive come eseguire la migrazione dell'implementazione di CoordinatorLayout per utilizzare Scaffold in Compose.

Passaggi per la migrazione

Per eseguire la migrazione da CoordinatorLayout a Scaffold, segui questi passaggi:

  1. Nello snippet di seguito, CoordinatorLayout contiene un AppBarLayout per contenere un ToolBar, un ViewPager e un FloatingActionButton. Commenta CoordinatorLayout e i relativi elementi secondari dalla gerarchia dell'interfaccia utente e aggiungi un ComposeView per sostituirlo.

    <!--  <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. Nel frammento o nell'attività, ottieni un riferimento al ComposeView appena aggiunto e chiama il metodo setContent. Nel corpo del metodo, imposta un Scaffold come contenuto:

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

  3. Nei contenuti del tuo Scaffold, aggiungi i contenuti principali della tua schermata. Poiché i contenuti principali nel codice XML riportato sopra sono un ViewPager2, utilizzeremo un HorizontalPager, che è l'equivalente di Compose. La funzione lambda content del Scaffold riceve anche un'istanza di PaddingValues che deve essere applicata alla radice dei contenuti. Puoi utilizzare Modifier.padding per applicare lo stesso PaddingValues al HorizontalPager.

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

  4. Utilizza gli altri spazi per i contenuti forniti da Scaffold per aggiungere altri elementi della schermata e per eseguire la migrazione delle visualizzazioni secondarie rimanenti. Puoi utilizzare lo slot topBar per aggiungere un TopAppBar e lo slot floatingActionButton per fornire 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 */ }
        }
    }

Casi d'uso comuni

Comprimire ed espandere le barre degli strumenti

Nel sistema di visualizzazione, per comprimere ed espandere la barra degli strumenti con CoordinatorLayout, utilizza un AppBarLayout come contenitore per la barra degli strumenti. Puoi quindi specificare un valore da Behavior a layout_behavior in XML nella visualizzazione scorrevole associata (ad esempio RecyclerView o NestedScrollView) per dichiarare in che modo la barra degli strumenti si comprime/si espande mentre scorri.

In Componi, puoi ottenere un effetto simile tramite un TopAppBarScrollBehavior. Ad esempio, per implementare una barra degli strumenti di compressione/espansione in modo che la barra degli strumenti venga visualizzata quando scorri verso l'alto, procedi nel seguente modo:

  1. Chiama TopAppBarDefaults.enterAlwaysScrollBehavior() per creare un TopAppBarScrollBehavior.
  2. Fornisci il TopAppBarScrollBehavior creato al TopAppBar.
  3. Collega NestedScrollConnection tramite Modifier.nestedScroll su Scaffold in modo che Scaffold possa ricevere eventi di scorrimento nidificati mentre i contenuti scorrevoli scorrono verso l'alto/verso il basso. In questo modo, la barra delle app contenuta può essere chiusa/aperta in modo appropriato man mano che i contenuti scorrono.

    // 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 */
        // ...
    }

Personalizzare l'effetto di scorrimento di chiusura/espansione

Puoi fornire diversi parametri per enterAlwaysScrollBehavior per personalizzare l'effetto di animazione di collasso/espansione. TopAppBarDefaults fornisce anche altri TopAppBarScrollBehavior, come exitUntilCollapsedScrollBehavior, che espande la barra delle app solo quando scorri i contenuti fino in fondo.

Per creare un effetto completamente personalizzato (ad esempio un effetto parallasse), puoi anche creare il tuo NestedScrollConnection e compensare manualmente la barra degli strumenti man mano che i contenuti scorrono. Per un esempio di codice, consulta l'esempio di scorrimento nidificato su AOSP.

Cassettiere

Con le visualizzazioni, puoi implementare un menu a scomparsa utilizzando un DrawerLayout come visualizzazione principale. A sua volta, CoordinatorLayout è una visualizzazione secondaria di DrawerLayout. DrawerLayout contiene anche un'altra vista secondaria, ad esempio NavigationView, per visualizzare le opzioni di navigazione nel riquadro.

In Componi, puoi implementare un riquadro di navigazione utilizzando il composable ModalNavigationDrawer. ModalNavigationDrawer offre un drawerContent slot per il riquadro e un content slot per i contenuti sullo schermo.

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

Per scoprire di più, consulta Cassetti.

Snackbar

Scaffold fornisce uno slot snackbarHost, che può accettare un composable SnackbarHost per visualizzare 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
    // ...
}

Per scoprire di più, consulta Barre di appezzo.

Scopri di più

Per ulteriori informazioni sulla migrazione di un CoordinatorLayout a Compose, consulta le seguenti risorse: