CoordinatorLayout zu Compose migrieren

CoordinatorLayout ist ein ViewGroup, das komplexe, sich überschneidende und verschachtelte Layouts ermöglicht. Er wird als Container verwendet, um bestimmte Material Design-Interaktionen für darin enthaltene Ansichten zu ermöglichen, z. B. das Maximieren und Minimieren von Symbolleisten und unteren Seitenbereichen.

Die nächste Entsprechung für CoordinatorLayout in Compose ist Scaffold. Ein Scaffold bietet Content-Slots, um Materialkomponenten in gängige Bildschirmmuster und ‑interaktionen zu kombinieren. Auf dieser Seite wird beschrieben, wie Sie Ihre CoordinatorLayout-Implementierung migrieren, um Scaffold in Compose zu verwenden.

Migrationsschritte

So migrieren Sie CoordinatorLayout zu Scaffold:

  1. Im folgenden Snippet enthält CoordinatorLayout ein AppBarLayout, das eine ToolBar, eine ViewPager und eine FloatingActionButton enthält. Kommentieren Sie die CoordinatorLayout und ihre untergeordneten Elemente aus der UI-Hierarchie und fügen Sie eine ComposeView hinzu, um sie zu ersetzen.

    <!--  <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 content-Lambda des Scaffold erhält außerdem eine Instanz von PaddingValues, die auf den Inhaltsstamm angewendet werden soll. Mit Modifier.padding können Sie dieselbe PaddingValues auf die HorizontalPager anwenden.

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

  4. Verwenden Sie andere Inhaltsslots, die Scaffold bietet, um weitere Bildschirmelemente hinzuzufügen und die verbleibenden untergeordneten Ansichten zu migrieren. Sie können den Slot topBar verwenden, um einen 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 im Ansichtssystem die Symbolleiste mit CoordinatorLayout minimieren und maximieren möchten, verwenden Sie einen AppBarLayout als Container für die Symbolleiste. Sie können dann in XML in der zugehörigen scrollbaren Ansicht (z. B. RecyclerView oder NestedScrollView) ein Behavior bis layout_behavior angeben, um festzulegen, wie die Symbolleiste beim Scrollen minimiert oder maximiert wird.

In Compose können Sie einen ähnlichen Effekt mit einem TopAppBarScrollBehavior erzielen. So implementieren Sie beispielsweise eine minimierbare/maximierbare Symbolleiste, die angezeigt wird, wenn Sie nach oben scrollen:

  1. Rufen Sie TopAppBarDefaults.enterAlwaysScrollBehavior() auf, um einen TopAppBarScrollBehavior zu erstellen.
  2. Geben Sie die erstellte TopAppBarScrollBehavior an die TopAppBar weiter.
  3. Verbinden Sie die NestedScrollConnection über Modifier.nestedScroll mit der Scaffold, damit der Scaffold verschachtelte Scroll-Ereignisse empfangen kann, wenn der scrollbare Inhalt nach oben oder unten gescrollt wird. 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 */
        // ...
    }

Scrolleffekt für minimierte/maximierte Bereiche anpassen

Sie können mehrere Parameter für enterAlwaysScrollBehavior angeben, um den Animationseffekt für das Zusammen- und Auseinanderfalten anzupassen. TopAppBarDefaults bietet auch andere TopAppBarScrollBehavior wie exitUntilCollapsedScrollBehavior, mit dem sich die App-Leiste nur maximiert, wenn der Inhalt ganz nach unten gescrollt wird.

Wenn Sie einen vollständig benutzerdefinierten Effekt erstellen möchten (z. B. einen Paralax-Effekt), können Sie auch Ihre eigene NestedScrollConnection erstellen und die Symbolleiste beim Scrollen der Inhalte manuell versetzen. Ein Codebeispiel finden Sie im Beispiel für verschachtelte Scrollansicht in AOSP.

Schubladen

Mithilfe von Ansichten können Sie eine Navigationsleiste implementieren, indem Sie DrawerLayout als Stammansicht verwenden. Die CoordinatorLayout ist wiederum eine untergeordnete Ansicht der DrawerLayout. Die DrawerLayout enthält auch eine weitere untergeordnete Ansicht, z. B. eine NavigationView, um die Navigationsoptionen im Navigationsmenü anzuzeigen.

In Compose können Sie eine Navigationsleiste mit dem ModalNavigationDrawer-Komponent implementieren. ModalNavigationDrawer bietet einen drawerContent-Steckplatz für die Schublade und einen content-Steckplatz für den Inhalt des Bildschirms.

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

Weitere Informationen finden Sie unter Schubladen.

Snackbars

Scaffold bietet einen snackbarHost-Slot, in den ein SnackbarHost-Komposit aufgenommen werden kann, um ein 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 finden Sie unter Snackbars.

Weitere Informationen

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