Di chuyển CoordinatorLayout sang Compose

CoordinatorLayout là một ViewGroup cho phép phức tạp, chồng chéo và bố cục lồng nhau. Được dùng làm vùng chứa để hỗ trợ một số Material Design cụ thể hoạt động tương tác, chẳng hạn như mở rộng/thu gọn thanh công cụ và bảng dưới cùng cho Chế độ xem nằm trong đó.

Trong Compose, thành phần tương đương gần nhất với CoordinatorLayout là một Scaffold. Scaffold cung cấp các ô nội dung để kết hợp Material Các thành phần thành các mẫu màn hình và hoạt động tương tác phổ biến. Trang này mô tả cách bạn có thể di chuyển cách triển khai CoordinatorLayout để sử dụng Scaffold trong Soạn thư.

Các bước di chuyển

Để di chuyển CoordinatorLayout sang Scaffold, hãy làm theo các bước sau:

  1. Trong đoạn mã dưới đây, CoordinatorLayout chứa AppBarLayout cho chứa ToolBar, ViewPagerFloatingActionButton. Nhận xét CoordinatorLayout và các phần tử con trong hệ phân cấp giao diện người dùng rồi thêm một ComposeView để thay thế thuộc tính này.

    <!--  <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. Trong Mảnh hoặc Hoạt động, hãy lấy thông tin tham chiếu đến ComposeView mà bạn vừa thêm và gọi phương thức setContent trên đó. Trong phần nội dung của phương thức, đặt Scaffold làm nội dung:

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

  3. Trong nội dung của Scaffold, hãy thêm nội dung chính của màn hình trong nó. Vì nội dung chính trong XML ở trên là ViewPager2, nên chúng ta sẽ sử dụng HorizontalPager, là phiên bản tương đương của Compose. Hàm lambda content của Scaffold cũng nhận được một thực thể PaddingValues cần phải là được áp dụng cho thư mục gốc của nội dung. Bạn có thể sử dụng Modifier.padding để áp dụng cùng một PaddingValues đến HorizontalPager.

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

  4. Dùng các khung nội dung khác mà Scaffold cung cấp để thêm các thành phần khác trên màn hình và di chuyển các Chế độ xem con còn lại. Bạn có thể sử dụng vị trí topBar để thêm TopAppBar và vị trí floatingActionButton để cung cấp 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 */ }
        }
    }

Các trường hợp sử dụng phổ biến

Thu gọn và mở rộng thanh công cụ

Trong hệ thống Khung hiển thị, để thu gọn và mở rộng thanh công cụ bằng CoordinatorLayout, bạn sẽ dùng AppBarLayout làm vùng chứa thanh công cụ. Sau đó, bạn có thể chỉ định một Behavior thông qua layout_behavior trong XML trên thành phần có thể cuộn Xem (như RecyclerView hoặc NestedScrollView) để khai báo cách thanh công cụ thu gọn/mở rộng khi bạn cuộn.

Trong Compose, bạn có thể đạt được hiệu quả tương tự thông qua TopAppBarScrollBehavior. Ví dụ: để triển khai tính năng thu gọn/mở rộng để thanh công cụ xuất hiện khi bạn cuộn lên, hãy làm theo các bước sau:

  1. Gọi TopAppBarDefaults.enterAlwaysScrollBehavior() để tạo một TopAppBarScrollBehavior.
  2. Cung cấp TopAppBarScrollBehavior đã tạo cho TopAppBar.
  3. Kết nối NestedScrollConnection qua Modifier.nestedScroll trên Scaffold để Scaffold có thể nhận các sự kiện cuộn lồng nhau dưới dạng nội dung có thể cuộn, cuộn lên/xuống. Bằng cách này, thanh ứng dụng được chứa trong thanh ứng dụng có thể thu gọn/mở rộng thích hợp khi nội dung cuộn.

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

Tuỳ chỉnh hiệu ứng cuộn thu gọn/mở rộng

Bạn có thể cung cấp một vài tham số cho enterAlwaysScrollBehavior để tuỳ chỉnh hiệu ứng ảnh động thu gọn/mở rộng. Ngoài ra, TopAppBarDefaults cung cấp TopAppBarScrollBehavior khác như exitUntilCollapsedScrollBehavior chỉ mở rộng thanh ứng dụng khi nội dung được cuộn xuống tận cùng.

Để tạo hiệu ứng hoàn toàn tuỳ chỉnh (ví dụ: hiệu ứng thị sai), bạn có thể bạn cũng có thể tạo NestedScrollConnection của riêng mình và bù trừ thanh công cụ theo cách thủ công là nội dung cuộn lên. Xem Mẫu cuộn lồng nhau trên AOSP để biết mã ví dụ.

Ngăn kéo

Với Khung hiển thị, bạn triển khai ngăn điều hướng bằng cách sử dụng DrawerLayout làm chế độ xem gốc. Đổi lại, CoordinatorLayout của bạn là khung hiển thị con của DrawerLayout. DrawerLayout cũng chứa một phần tử con khác khung hiển thị, chẳng hạn như NavigationView, để hiển thị các tuỳ chọn điều hướng trong ngăn.

Trong Compose, bạn có thể triển khai ngăn điều hướng bằng cách sử dụng Thành phần kết hợp ModalNavigationDrawer. ModalNavigationDrawer cung cấp Khe drawerContent cho ngăn và khe content cho màn hình nội dung.

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

Xem Ngăn kéo để tìm hiểu thêm.

Thanh thông báo nhanh

Scaffold cung cấp một ô snackbarHost có thể chấp nhận SnackbarHost thành phần kết hợp để hiển thị 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
    // ...
}

Xem Thanh thông báo nhanh để tìm hiểu thêm.

Tìm hiểu thêm

Để biết thêm thông tin về cách di chuyển CoordinatorLayout sang Compose, hãy xem các tài nguyên sau: