CoordinatorLayout zu Compose migrieren

CoordinatorLayout ist ein ViewGroup, der komplexe, überlappende und verschachtelte Layouts ermöglicht. Es wird als Container verwendet, um bestimmte Material Design-Interaktionen zu ermöglichen, z. B. das Maximieren/Minimieren von Symbolleisten und Tabellenblättern am unteren Rand für darin enthaltene Ansichten.

In der Funktion „Compose“ ist die Entsprechung für CoordinatorLayout ein Scaffold. Ein Scaffold bietet Inhaltsslots, um Materialkomponenten zu gängigen Bildschirmmustern und Interaktionen zu kombinieren. 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 CoordinatorLayout ein AppBarLayout für ToolBar, ViewPager und FloatingActionButton. Kommentieren Sie CoordinatorLayout und die untergeordneten Elemente aus der UI-Hierarchie aus und fügen Sie als Ersatz einen ComposeView 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 in Ihrer Aktivität einen Verweis auf das soeben hinzugefügte ComposeView ab und rufen Sie die setContent-Methode darauf auf. Legen Sie im Textkörper der Methode Scaffold als Inhalt fest:

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

  3. Füge im Inhalt von Scaffold den Hauptinhalt deines Bildschirms hinzu. Da der Hauptinhalt in der obigen XML-Datei ein ViewPager2 ist, verwenden wir HorizontalPager. Dies entspricht der Compose-Entsprechung. Das Lambda content des Scaffold empfängt ebenfalls eine Instanz von PaddingValues, die auf den Inhaltsstamm angewendet werden sollte. Sie können Modifier.padding verwenden, um dieselbe PaddingValues auf HorizontalPager anzuwenden.

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

  4. Verwende andere Inhaltsflächen, die von Scaffold bereitgestellt werden, 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 bereitzustellen.

    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

Zum Minimieren und Maximieren der Symbolleiste mit CoordinatorLayout verwenden Sie im View-System ein AppBarLayout als Container für die Symbolleiste. Anschließend können Sie einen Behavior bis layout_behavior in XML für die zugehörige scrollbare Ansicht (z. B. RecyclerView oder NestedScrollView) angeben, um zu deklarieren, wie die Symbolleiste beim Scrollen ein-/ausgeblendet wird.

In der Funktion „Compose“ können Sie einen ähnlichen Effekt mit einem TopAppBarScrollBehavior erzielen. Wenn Sie beispielsweise eine Symbolleiste zum Minimieren und Maximieren implementieren möchten, damit sie beim Scrollen nach oben erscheint, gehen Sie so vor:

  1. Rufen Sie TopAppBarDefaults.enterAlwaysScrollBehavior() auf, um eine TopAppBarScrollBehavior zu erstellen.
  2. Geben Sie die erstellte TopAppBarScrollBehavior an TopAppBar an.
  3. Verbinden Sie NestedScrollConnection über Modifier.nestedScroll in Scaffold, damit das Scaffold verschachtelte Scroll-Ereignisse empfangen kann, wenn der scrollbare Inhalt nach oben/unten scrollt. So kann die enthaltene App-Leiste beim Scrollen des Inhalts entsprechend minimiert/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 „Maximieren/Minimieren“ anpassen

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

Wenn Sie einen komplett benutzerdefinierten Effekt erstellen möchten (z. B. einen Parallaxe-Effekt), können Sie auch ein eigenes NestedScrollConnection erstellen und die Symbolleiste manuell verschieben, wenn der Inhalt scrollt. Ein Codebeispiel finden Sie im Beispiel für verschachteltes Scrollen auf AOSP.

Schubladen

Mit Ansichten implementieren Sie eine Navigationsleiste, indem Sie DrawerLayout als Stammansicht verwenden. Ihr CoordinatorLayout ist wiederum eine untergeordnete Ansicht von DrawerLayout. Das DrawerLayout enthält auch eine weitere untergeordnete Ansicht, z. B. NavigationView, in der die Navigationsoptionen in der Leiste angezeigt werden.

In Compose können Sie mithilfe der zusammensetzbaren Funktion ModalNavigationDrawer eine Navigationsleiste implementieren. ModalNavigationDrawer bietet eine drawerContent-Fläche für die Leiste und eine content-Fläche 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

Snackbars

Scaffold stellt einen snackbarHost-Slot bereit, der eine zusammensetzbare SnackbarHost-Funktion zum Anzeigen eines Snackbar akzeptieren kann.

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 zum Migrieren von CoordinatorLayout zu Compose finden Sie in den folgenden Ressourcen: