CoordinatorLayout zu Compose migrieren

CoordinatorLayout ist ein ViewGroup, das komplexe, überlappende und verschachtelte Layouts ermöglicht. Er wird als Container verwendet, um bestimmte Material Design-Interaktionen wie das Maximieren/Minimieren von Symbolleisten und Ansichten am unteren Rand für die darin enthaltenen Ansichten zu ermöglichen.

In Compose ist das nächste Äquivalent zu einem CoordinatorLayout ein Scaffold. Ein Scaffold bietet Inhalts-Slots, um Material-Komponenten in gängigen Bildschirmmustern 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 ein ToolBar, ein ViewPager und ein FloatingActionButton enthält. Kommentieren Sie die CoordinatorLayout und ihre untergeordneten Elemente aus der UI-Hierarchie aus und fügen Sie stattdessen eine ComposeView hinzu.

    ```xml

    <!-- AppBarLayout contents here -->
    

    ```

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

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

  3. Fügen Sie im Inhalt von Scaffold den primären Inhalt des Bildschirms hinzu. Da der Hauptinhalt im XML-Code oben ein ViewPager2 ist, verwenden wir ein HorizontalPager, das Compose-Äquivalent. Der content-Lambda-Ausdruck von Scaffold empfängt auch eine Instanz von PaddingValues, die auf das Stammverzeichnis des Inhalts angewendet werden sollte. Sie können Modifier.padding verwenden, um dieselbe PaddingValues auf die 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 Inhalts-Slots, um weitere Bildschirmelemente hinzuzufügen und die verbleibenden untergeordneten Ansichten zu migrieren. Mit dem Slot topBar können Sie ein TopAppBar und mit dem Slot floatingActionButton ein FloatingActionButton hinzufü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

Im View-System verwenden Sie ein AppBarLayout als Container für die Symbolleiste, um die Symbolleiste mit CoordinatorLayout zu minimieren und zu maximieren. Anschließend kannst du in der XML-Datei der zugehörigen scrollbaren Ansicht (z. B. RecyclerView oder NestedScrollView) einen Behavior über layout_behavior 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 minimierbare/maximierbare Symbolleiste, die beim Scrollen nach oben angezeigt wird:

  1. Rufen Sie TopAppBarDefaults.enterAlwaysScrollBehavior() auf, um eine TopAppBarScrollBehavior zu erstellen.
  2. Stellen Sie dem TopAppBar die erstellte TopAppBarScrollBehavior zur Verfügung.
  3. Verbinde den NestedScrollConnection über Modifier.nestedScroll mit dem 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 des Inhalts 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 */
        // ...
    }

Scrolleffekt zum Minimieren/Maximieren anpassen

Sie können mehrere Parameter für enterAlwaysScrollBehavior angeben, um den Animationseffekt für das Minimieren/Maximieren anzupassen. TopAppBarDefaults bietet auch andere TopAppBarScrollBehavior, z. B. exitUntilCollapsedScrollBehavior, wodurch die App-Leiste nur maximiert wird, wenn der Inhalt ganz nach unten gescrollt wird.

Wenn du einen vollständig benutzerdefinierten Effekt erstellen möchtest (z. B. einen Parallax-Effekt), kannst du auch ein eigenes NestedScrollConnection erstellen und die Symbolleiste manuell verschieben, während der Inhalt gescrollt wird. Ein Codebeispiel finden Sie im Beispiel für verschachteltes Scrollen im AOSP.

Schubladen

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

In Compose können Sie eine Navigationsleiste mit der zusammensetzbaren Funktion ModalNavigationDrawer implementieren. ModalNavigationDrawer bietet einen drawerContent-Slot für die Leiste und einen content-Slot 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 Seitenleisten.

Snackbars

Scaffold bietet einen snackbarHost-Slot, der eine SnackbarHost-komponierbare Funktion 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 von CoordinatorLayout zu Compose finden Sie in den folgenden Ressourcen: