CoordinatorLayout zu Compose migrieren

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

In Compose ist die nächstgelegene Entsprechung von CoordinatorLayout ein Scaffold. Scaffold bietet Content-Slots, mit denen Material-Komponenten zu gängigen Bildschirmmustern und Interaktionen kombiniert werden können. Auf dieser Seite wird beschrieben, wie Sie Ihre CoordinatorLayout-Implementierung migrieren können, um Scaffold in Compose zu verwenden.

Migrationsschritte

So migrieren Sie CoordinatorLayout zu Scaffold:

  1. Im Snippet unten enthält CoordinatorLayout ein AppBarLayout für eine ToolBar, einen ViewPager und einen FloatingActionButton. Kommentieren Sie CoordinatorLayout und seine untergeordneten Elemente in Ihrer UI-Hierarchie aus und fügen Sie stattdessen eine 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 Ihrer Aktivität einen Verweis auf die gerade hinzugefügte ComposeView ab und rufen Sie die Methode setContent auf. Legen Sie im Textkörper der Methode ein Scaffold als Inhalt fest:

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

  3. Fügen Sie im Inhalt von Scaffold die primären Inhalte des Bildschirms hinzu. Da der primäre Inhalt im obigen XML-Code ein ViewPager2 ist, verwenden wir einen HorizontalPager, der die Compose-Entsprechung dafür ist. Die content-Lambda von Scaffold erhält auch eine Instanz von PaddingValues, die auf das Stammverzeichnis des Inhalts angewendet werden sollte. Mit Modifier.padding können Sie dieselben PaddingValues auf 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 Content-Slots, die Scaffold bietet, 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 ein- und ausblenden

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

In Compose können Sie einen ähnlichen Effekt mit einem TopAppBarScrollBehavior erzielen. So implementieren Sie beispielsweise eine ein- und ausblendbare Symbolleiste, die beim Scrollen nach oben angezeigt wird:

  1. Rufen Sie TopAppBarDefaults.enterAlwaysScrollBehavior() auf, um ein TopAppBarScrollBehavior zu erstellen.
  2. Geben Sie das erstellte TopAppBarScrollBehavior an TopAppBar weiter.
  3. Verbinden Sie NestedScrollConnection über Modifier.nestedScroll mit dem Scaffold, damit das Scaffold verschachtelte Scrollereignisse empfangen kann, wenn der scrollbare Inhalt nach oben oder unten gescrollt wird. So kann die enthaltene App-Leiste beim Scrollen des Inhalts 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 des Scroll-Effekts anpassen

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

Wenn Sie einen vollständig benutzerdefinierten Effekt erstellen möchten (z. B. einen Parallax-Effekt), können Sie auch eine eigene NestedScrollConnection erstellen und die Symbolleiste beim Scrollen des Inhalts manuell verschieben. Ein Codebeispiel finden Sie im Beispiel für verschachteltes Scrollen auf AOSP.

Schubladen

Mit Ansichten implementieren Sie eine Navigationsleiste mit DrawerLayout als Stammansicht. Ihre CoordinatorLayout ist wiederum eine Kinderansicht von DrawerLayout. Das DrawerLayout enthält auch eine weitere untergeordnete Ansicht, z. B. eine NavigationView, um die Navigationsoptionen in der Schublade anzuzeigen.

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

Snackbars

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