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.

In Compose entspricht ein Scaffold am ehesten einem CoordinatorLayout. 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 den gerade hinzugefügten ComposeView ab und rufen Sie die Methode setContent darauf auf. Legen Sie im Body der Methode Scaffold als Inhalt fest:

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

  3. Fügen Sie den Hauptinhalt Ihres Bildschirms in den Inhalt Ihrer Scaffold 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. Im Slot topBar können Sie ein TopAppBar und im Slot floatingActionButton ein FloatingActionButton einfügen.

    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 das Scaffold verschachtelte Scrollereignisse empfangen kann, wenn der scrollbare Inhalt nach oben oder unten gescrollt wird. So kann die App-Leiste beim Scrollen der Inhalte entsprechend minimiert oder maximiert werden.

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

Effekt für das Zusammen- und Auseinanderziehen von Elementen 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: