Przenieś układ koordynatora do tworzenia wiadomości

CoordinatorLayout to ViewGroup, który umożliwia tworzenie złożonych, nakładających się i zagnieżdżonych układów. Służy jako kontener, który umożliwia określone interakcje Material Design, takie jak rozwijanie i zwijanie pasków narzędzi oraz arkuszy dolnych, w przypadku widoków zawartych w tym kontenerze.

W Compose najbliższym odpowiednikiem CoordinatorLayout jest Scaffold. Scaffold zapewnia miejsca na treści, w których można łączyć komponenty Material w typowych wzorcach ekranów i interakcjach. Na tej stronie dowiesz się, jak przenieść implementację CoordinatorLayout, aby używać Scaffold w Compose.

Etapy migracji

Aby przenieść CoordinatorLayout do Scaffold, wykonaj te czynności:

  1. W poniższym fragmencie kodu element CoordinatorLayout zawiera element AppBarLayout, który zawiera elementy ToolBar, ViewPager i FloatingActionButton. Usuń CoordinatorLayout i jego elementy podrzędne z hierarchii interfejsu i dodaj element ComposeView, aby go zastąpić.

    <!--  <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. W fragmencie lub aktywności uzyskaj odwołanie do elementu ComposeView, który właśnie został dodany, i wywołaj na nim metodę setContent. W treści metody ustaw Scaffold jako jej zawartość:

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

  3. W treści Scaffold dodaj główną zawartość ekranu. Główna treść w powyższym kodzie XML to ViewPager2, więc użyjemy elementu HorizontalPager, który jest jego odpowiednikiem w Compose. content lambda Scaffold otrzymuje też instancję PaddingValues, która powinna zostać zastosowana do głównego elementu treści. Możesz użyć Modifier.padding, aby zastosować ten sam PaddingValues do HorizontalPager.

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

  4. Użyj innych miejsc na treści, które udostępnia Scaffold, aby dodać więcej elementów ekranu i przenieść pozostałe widoki podrzędne. W slocie topBar możesz dodać TopAppBar, a w slocie floatingActionButton – FloatingActionButton.

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

Częste przypadki użycia

Zwijanie i rozwijanie pasków narzędzi

W systemie View, aby zwinąć i rozwinąć pasek narzędzi za pomocą CoordinatorLayout, używasz elementu AppBarLayout jako kontenera paska narzędzi. Następnie możesz określić wartości od Behavior do layout_behavior w XML w powiązanym widoku z możliwością przewijania (np. RecyclerView lub NestedScrollView), aby zadeklarować, jak pasek narzędzi ma się zwijać lub rozwijać podczas przewijania.

W Compose możesz uzyskać podobny efekt za pomocą TopAppBarScrollBehavior. Aby na przykład wdrożyć zwijany/rozwijany pasek narzędzi, który będzie się pojawiać podczas przewijania w górę, wykonaj te czynności:

  1. Wywołaj funkcję TopAppBarDefaults.enterAlwaysScrollBehavior(), aby utworzyć TopAppBarScrollBehavior.
  2. Przekaż utworzony TopAppBarScrollBehavior do TopAppBar.
  3. Połącz NestedScrollConnection za pomocą Modifier.nestedScroll na Scaffold, aby element Scaffold mógł odbierać zagnieżdżone zdarzenia przewijania, gdy zawartość z możliwością przewijania jest przewijana w górę lub w dół. Dzięki temu pasek aplikacji może się odpowiednio zwijać i rozwijać podczas przewijania treści.

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

Dostosowywanie efektu zwijania/rozwijania podczas przewijania

Możesz podać kilka parametrów dla enterAlwaysScrollBehavior, aby dostosować efekt animacji zwijania/rozwijania. TopAppBarDefaults udostępnia też inne TopAppBarScrollBehavior, takie jak exitUntilCollapsedScrollBehavior, który rozwija pasek aplikacji tylko wtedy, gdy zawartość jest przewinięta do samego dołu.

Aby utworzyć całkowicie niestandardowy efekt (np. efekt paralaksy), możesz też utworzyć własny NestedScrollConnection i ręcznie przesunąć pasek narzędzi podczas przewijania treści. Przykładowy kod znajdziesz w przykładzie zagnieżdżonego przewijania w AOSP.

Szuflady

W przypadku widoków menu nawigacyjne implementujesz za pomocą elementu DrawerLayout jako widoku głównego. Z kolei CoordinatorLayout jest widokiem podrzędnym elementu DrawerLayout. DrawerLayout zawiera też inny widok podrzędny, np. NavigationView, który wyświetla opcje nawigacji w panelu.

W Compose możesz wdrożyć panel nawigacyjny za pomocą funkcji kompozycyjnej ModalNavigationDrawer. ModalNavigationDrawer ma drawerContent miejsce na szufladę i content miejsce na zawartość ekranu.

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

Więcej informacji znajdziesz w sekcji Szuflady.

Paski powiadomień

Scaffold udostępnia snackbarHost, które może akceptować SnackbarHost kompozycję do wyświetlania Snackbar.

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

Więcej informacji znajdziesz w sekcji Paski z informacjami.

Więcej informacji

Więcej informacji o migracji CoordinatorLayout do Compose znajdziesz w tych materiałach: