CoordinatorLayout zu Compose migrieren

CoordinatorLayout ist eine ViewGroup, die komplexe, sich überschneidende und verschachtelte Layouts ermöglicht. Es wird als Container verwendet, um bestimmte Material Design-Interaktionen für darin enthaltene Ansichten zu ermöglichen, z. B. Symbolleisten zum Maximieren und Minimieren und Tabellenblätter am unteren Rand.

Die nächste Entsprechung für CoordinatorLayout in Compose ist Scaffold. Ein Scaffold bietet Inhaltsbereiche zum Kombinieren von Materialkomponenten zu gängigen Bildschirmmustern und Interaktionen. Auf dieser Seite wird beschrieben, wie Sie Ihre CoordinatorLayout-Implementierung zur Verwendung von Scaffold in Composer migrieren können.

Migrationsschritte

So migrieren Sie CoordinatorLayout zu Scaffold:

  1. Im folgenden Snippet enthält das CoordinatorLayout ein AppBarLayout zur Aufnahme von ToolBar, ViewPager und FloatingActionButton. Kommentieren Sie das CoordinatorLayout und die untergeordneten Elemente aus Ihrer UI-Hierarchie aus und fügen Sie ein ComposeView als Ersatz hinzu.

    <!--  <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. Rufen Sie in Ihrem Fragment oder Ihrer Aktivität einen Verweis auf das gerade hinzugefügte ComposeView-Objekt ab und rufen Sie dafür die Methode setContent auf. Legen Sie im Hauptteil der Methode ein Scaffold als Inhalt fest:

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

  3. Fügen Sie in den Scaffold den Hauptinhalt Ihres Bildschirms ein. Da der Hauptinhalt in der obigen XML-Datei ein ViewPager2 ist, verwenden wir ein HorizontalPager, das dem Compose-Äquivalent entspricht. Das Lambda content von Scaffold empfängt auch eine Instanz von PaddingValues, die auf das Inhaltsstammverzeichnis angewendet werden sollte. Sie können Modifier.padding verwenden, um dasselbe PaddingValues auf HorizontalPager anzuwenden.

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

  4. Verwenden Sie andere von Scaffold bereitgestellte Inhaltsbereiche, um weitere Bildschirmelemente hinzuzufügen und die verbleibenden untergeordneten Ansichten zu migrieren. Sie können den Slot topBar verwenden, um ein TopAppBar hinzuzufügen, und den Slot floatingActionButton, um einen FloatingActionButton anzugeben.

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

Gängige Anwendungsfälle

Symbolleisten minimieren und maximieren

Wenn Sie die Symbolleiste im Ansichtssystem mit CoordinatorLayout minimieren und maximieren möchten, verwenden Sie ein AppBarLayout als Container für die Symbolleiste. Du kannst dann in XML ein Behavior bis layout_behavior in der zugehörigen scrollbaren Ansicht (z. B. RecyclerView oder NestedScrollView) angeben, um festzulegen, wie die Symbolleiste beim Scrollen minimiert/maximiert wird.

In Compose können Sie einen ähnlichen Effekt mit einem TopAppBarScrollBehavior erzielen. So implementieren Sie beispielsweise eine Symbolleiste zum Minimieren und Maximieren, damit die Symbolleiste angezeigt wird, wenn Sie nach oben scrollen:

  1. Rufen Sie TopAppBarDefaults.enterAlwaysScrollBehavior() auf, um eine TopAppBarScrollBehavior zu erstellen.
  2. Stellen Sie den erstellten TopAppBarScrollBehavior für den TopAppBar bereit.
  3. Verbinde das NestedScrollConnection über Modifier.nestedScroll auf dem Scaffold, damit das Scaffold verschachtelte Scroll-Ereignisse empfangen kann, wenn der scrollbare Inhalt nach oben/unten scrollt. Auf diese Weise kann die enthaltene App-Leiste entsprechend minimiert/erweitert werden, wenn der Inhalt scrollt.

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

Minimieren/Maximieren des Scrolleffekts anpassen

Sie können mehrere Parameter für enterAlwaysScrollBehavior angeben, um den Effekt der Animation zum Minimieren und Maximieren anzupassen. TopAppBarDefaults bietet auch andere TopAppBarScrollBehavior wie exitUntilCollapsedScrollBehavior, mit denen die App-Leiste nur maximiert wird, wenn der Inhalt ganz nach unten gescrollt wird.

Wenn Sie einen vollständig benutzerdefinierten Effekt erstellen möchten (z. B. einen Parallaxe-Effekt), können Sie auch Ihr eigenes NestedScrollConnection erstellen und die Symbolleiste beim Scrollen des Inhalts manuell verschieben. Ein Codebeispiel finden Sie unter Verschachteltes Scrollbeispiel auf AOSP.

Schubladen

Mithilfe von „Views“ implementieren Sie eine Navigationsleiste und verwenden dazu DrawerLayout als Stammansicht. Ihr CoordinatorLayout wiederum ist eine untergeordnete Ansicht von DrawerLayout. DrawerLayout enthält auch eine weitere untergeordnete Ansicht, z. B. NavigationView, um die Navigationsoptionen in der Leiste anzuzeigen.

In Compose können Sie mit der zusammensetzbaren Funktion ModalNavigationDrawer eine Navigationsleiste implementieren. ModalNavigationDrawer bietet einen drawerContent-Slot für die Leiste und einen content-Slot für den Bildschirminhalt.

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

Weitere Informationen finden Sie unter Drawer.

Snackbars

Scaffold stellt einen snackbarHost-Slot bereit, der eine zusammensetzbare SnackbarHost-Funktion annehmen kann, um eine Snackbar anzuzeigen.

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

Weitere Informationen findest du unter Snackbars.

Weitere Informationen

Weitere Informationen zur Migration einer CoordinatorLayout zu Compose finden Sie in den folgenden Ressourcen: