CoordinatorLayout zu Compose migrieren

CoordinatorLayout ist ein ViewGroup, das komplexe, sich überschneidende und verschachtelte Layouts ermöglicht. Sie wird als Container verwendet, um bestimmte Material Design-Interaktionen für die darin enthaltenen Ansichten zu ermöglichen, z. B. das Ein- und Ausblenden von Symbolleisten und Bottom Sheets.

In Compose ist die Scaffold das Äquivalent zu einer CoordinatorLayout. Ein Scaffold bietet Inhalts-Slots zum Kombinieren von Material-Komponenten in gängigen Bildschirmmustern und Interaktionen. Auf dieser Seite wird beschrieben, wie Sie Ihre CoordinatorLayout-Implementierung für die Verwendung von Scaffold in Compose migrieren können.

Migrationsschritte

So migrieren Sie CoordinatorLayout zu Scaffold:

  1. Im folgenden Snippet enthält CoordinatorLayout ein AppBarLayout mit einem ToolBar, einem ViewPager und einem FloatingActionButton. Kommentieren Sie das CoordinatorLayout und seine untergeordneten Elemente in der UI-Hierarchie aus und fügen Sie stattdessen ein ComposeView ein.

    ```xml

    <!-- AppBarLayout contents here -->
    

    ```

  2. Rufen Sie in Ihrem Fragment oder Ihrer Aktivität eine Referenz auf das ComposeView ab, das Sie gerade hinzugefügt haben, und rufen Sie die Methode setContent dafür auf. Legen Sie im Body der Methode ein Scaffold als Inhalt fest:

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

  3. Fügen Sie im Inhalt Ihres Scaffold-Objekts die primären Inhalte des Bildschirms ein. Da der primäre Inhalt im XML-Code oben ein ViewPager2 ist, verwenden wir ein HorizontalPager, das Compose-Äquivalent. Die content-Lambdafunktion des Scaffold erhält auch 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 Inhalts-Slots, die Scaffold bereitstellt, um weitere Bildschirmelemente hinzuzufügen und die verbleibenden untergeordneten Ansichten zu migrieren. Im Slot topBar können Sie eine TopAppBar und im Slot floatingActionButton eine FloatingActionButton angeben.

    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

Im View-System verwenden Sie ein AppBarLayout als Container für die Symbolleiste, um die Symbolleiste mit CoordinatorLayout ein- und auszublenden. Anschließend können Sie über layout_behavior in XML für die zugehörige scrollbare Ansicht (z. B. RecyclerView oder NestedScrollView) eine Behavior angeben, um festzulegen, wie die Symbolleiste beim Scrollen ein- und ausgeblendet wird.

In Compose können Sie einen ähnlichen Effekt mit einer TopAppBarScrollBehavior erzielen. Wenn Sie beispielsweise eine ein- und ausblendbare Symbolleiste implementieren möchten, die beim Scrollen nach oben angezeigt wird, gehen Sie so vor:

  1. Rufen Sie TopAppBarDefaults.enterAlwaysScrollBehavior() auf, um ein TopAppBarScrollBehavior zu erstellen.
  2. Stellen Sie die erstellte TopAppBarScrollBehavior für die TopAppBar bereit.
  3. Verbinden Sie NestedScrollConnection über Modifier.nestedScroll auf der Scaffold, damit das Scaffold verschachtelte Scroll-Ereignisse empfangen kann, wenn der scrollbare Inhalt nach oben oder unten gescrollt wird. So kann die enthaltene App-Leiste beim Scrollen der Inhalte entsprechend ein- und ausgeblendet 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 */
        // ...
    }

Ein- und Ausblenden-Scrolleffekt anpassen

Sie können mehrere Parameter für enterAlwaysScrollBehavior angeben, um den Ein- und Ausblendungseffekt anzupassen. TopAppBarDefaults bietet auch andere TopAppBarScrollBehavior wie exitUntilCollapsedScrollBehavior, die die App-Leiste nur dann maximieren, wenn der Inhalt ganz nach unten gescrollt wird.

Wenn Sie einen vollständig benutzerdefinierten Effekt erstellen möchten, z. B. einen Parallaxeneffekt, können Sie auch ein eigenes NestedScrollConnection erstellen und die Symbolleiste manuell versetzen, während der Inhalt gescrollt wird. Ein Codebeispiel finden Sie im Beispiel für verschachteltes Scrollen auf AOSP.

Schubladen

Mit Views implementieren Sie eine Navigationsleiste, indem Sie ein DrawerLayout als Stammansicht verwenden. Ihr CoordinatorLayout ist wiederum eine Kinderansicht von DrawerLayout. Die DrawerLayout enthält auch eine weitere untergeordnete Ansicht, z. B. eine NavigationView, um die Navigationsoptionen in der Seitenleiste anzuzeigen.

In Compose können Sie eine Navigationsleiste mit der komponierbaren Funktion ModalNavigationDrawer implementieren. ModalNavigationDrawer bietet einen drawerContent-Slot für die Schublade und einen content-Slot für den Inhalt des Displays.

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, der ein SnackbarHost-Composable akzeptieren 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 eines CoordinatorLayout zu Compose finden Sie in den folgenden Ressourcen: