Sử dụng bộ sưu tập để sắp xếp ngăn nắp các trang
Lưu và phân loại nội dung dựa trên lựa chọn ưu tiên của bạn.
Thành phần kéo để làm mới cho phép người dùng kéo xuống ở đầu nội dung của ứng dụng để làm mới dữ liệu.
Nền tảng API
Sử dụng thành phần kết hợp PullToRefreshBox để triển khai tính năng kéo để làm mới, đóng vai trò là vùng chứa cho nội dung có thể cuộn. Các tham số chính sau đây kiểm soát hành vi và giao diện làm mới:
isRefreshing: Một giá trị boolean cho biết liệu thao tác làm mới có đang diễn ra hay không.
onRefresh: Một hàm lambda thực thi khi người dùng bắt đầu làm mới.
indicator: Tuỳ chỉnh chỉ báo mà hệ thống vẽ trên thao tác kéo để làm mới.
Ví dụ cơ bản
Đoạn mã này minh hoạ cách sử dụng cơ bản của PullToRefreshBox:
Màu của chỉ báo được tuỳ chỉnh thông qua các thuộc tính containerColor và color trong tham số indicator.
rememberPullToRefreshState() quản lý trạng thái của thao tác làm mới.
Bạn sử dụng trạng thái này cùng với tham số indicator.
Kết quả
Video này minh hoạ một cách triển khai thao tác kéo để làm mới bằng chỉ báo có màu:
Hình 2. Một cách triển khai tính năng kéo để làm mới có kiểu tuỳ chỉnh.
Ví dụ nâng cao: Tạo chỉ báo hoàn toàn tuỳ chỉnh
Bạn có thể tạo các chỉ báo tuỳ chỉnh phức tạp bằng cách tận dụng các thành phần kết hợp và ảnh động hiện có.Đoạn mã này minh hoạ cách tạo một chỉ báo hoàn toàn tuỳ chỉnh trong quá trình triển khai tính năng kéo để làm mới:
Đoạn mã trước đó đã sử dụng Indicator do thư viện cung cấp. Đoạn mã này tạo một thành phần kết hợp chỉ báo tuỳ chỉnh có tên là MyCustomIndicator. Trong thành phần kết hợp này, đối tượng sửa đổi pullToRefreshIndicator sẽ xử lý việc định vị và kích hoạt quá trình làm mới.
Như trong đoạn mã trước, ví dụ này trích xuất thực thể PullToRefreshState, vì vậy bạn có thể truyền cùng một thực thể cho cả PullToRefreshBox và pullToRefreshModifier.
Ví dụ này sử dụng màu vùng chứa và ngưỡng vị trí từ lớp PullToRefreshDefaults. Bằng cách này, bạn có thể sử dụng lại hành vi và kiểu mặc định từ thư viện Material, trong khi chỉ tuỳ chỉnh những phần tử mà bạn quan tâm.
MyCustomIndicator dùng Crossfade để chuyển đổi giữa biểu tượng đám mây và CircularProgressIndicator. Biểu tượng đám mây sẽ tăng kích thước khi người dùng kéo và chuyển sang biểu tượng CircularProgressIndicator khi hành động làm mới bắt đầu.
targetState sử dụng isRefreshing để xác định trạng thái cần hiển thị (biểu tượng đám mây hoặc chỉ báo tiến trình hình tròn).
animationSpec xác định một ảnh động tween cho hiệu ứng chuyển đổi, với thời lượng được chỉ định là CROSSFADE_DURATION_MILLIS.
state.distanceFraction biểu thị khoảng cách mà người dùng đã kéo xuống, từ 0f (không kéo) đến 1f (kéo hoàn toàn).
Đối tượng sửa đổi graphicsLayer sửa đổi tỷ lệ và độ trong suốt.
Kết quả
Video này cho thấy chỉ báo tuỳ chỉnh trong mã trước đó:
Hình 3. Một cách triển khai thao tác kéo để làm mới bằng chỉ báo tuỳ chỉnh.
Nội dung và mã mẫu trên trang này phải tuân thủ các giấy phép như mô tả trong phần Giấy phép nội dung. Java và OpenJDK là nhãn hiệu hoặc nhãn hiệu đã đăng ký của Oracle và/hoặc đơn vị liên kết của Oracle.
Cập nhật lần gần đây nhất: 2025-08-28 UTC.
[[["Dễ hiểu","easyToUnderstand","thumb-up"],["Giúp tôi giải quyết được vấn đề","solvedMyProblem","thumb-up"],["Khác","otherUp","thumb-up"]],[["Thiếu thông tin tôi cần","missingTheInformationINeed","thumb-down"],["Quá phức tạp/quá nhiều bước","tooComplicatedTooManySteps","thumb-down"],["Đã lỗi thời","outOfDate","thumb-down"],["Vấn đề về bản dịch","translationIssue","thumb-down"],["Vấn đề về mẫu/mã","samplesCodeIssue","thumb-down"],["Khác","otherDown","thumb-down"]],["Cập nhật lần gần đây nhất: 2025-08-28 UTC."],[],[],null,["The pull to refresh component allows users to drag downwards at the beginning of\nan app's content to refresh the data.\n| **Note:** [`PullToRefreshBox()`](/reference/kotlin/androidx/compose/material3/pulltorefresh/package-summary#PullToRefreshBox(kotlin.Boolean,kotlin.Function0,androidx.compose.ui.Modifier,androidx.compose.material3.pulltorefresh.PullToRefreshState,androidx.compose.ui.Alignment,kotlin.Function1,kotlin.Function1)) is experimental.\n\nAPI surface\n\nUse the [`PullToRefreshBox`](/reference/kotlin/androidx/compose/material3/pulltorefresh/package-summary#PullToRefreshBox(kotlin.Boolean,kotlin.Function0,androidx.compose.ui.Modifier,androidx.compose.material3.pulltorefresh.PullToRefreshState,androidx.compose.ui.Alignment,kotlin.Function1,kotlin.Function1)) composable to implement pull-to-refresh, which\nacts as a container for your scrollable content. The following key parameters\ncontrol the refresh behavior and appearance:\n\n- `isRefreshing`: A boolean value indicating whether the refresh action is in progress.\n- `onRefresh`: A lambda function that executes when the user initiates a refresh.\n- `indicator`: Customizes the indicator that the system draws on pull-to-refresh.\n\nBasic example\n\nThis snippet demonstrates basic usage of `PullToRefreshBox`:\n\n\n```kotlin\n@Composable\nfun PullToRefreshBasicSample(\n items: List\u003cString\u003e,\n isRefreshing: Boolean,\n onRefresh: () -\u003e Unit,\n modifier: Modifier = Modifier\n) {\n PullToRefreshBox(\n isRefreshing = isRefreshing,\n onRefresh = onRefresh,\n modifier = modifier\n ) {\n LazyColumn(Modifier.fillMaxSize()) {\n items(items) {\n ListItem({ Text(text = it) })\n }\n }\n }\n}https://github.com/android/snippets/blob/7a0ebbee11495f628cf9d574f6b6069c2867232a/compose/snippets/src/main/java/com/example/compose/snippets/components/PullToRefreshBox.kt#L92-L110\n```\n\n\u003cbr /\u003e\n\nKey points about the code\n\n- `PullToRefreshBox` wraps a [`LazyColumn`](/reference/kotlin/androidx/compose/foundation/lazy/package-summary#LazyColumn(androidx.compose.ui.Modifier,androidx.compose.foundation.lazy.LazyListState,androidx.compose.foundation.layout.PaddingValues,kotlin.Boolean,androidx.compose.foundation.layout.Arrangement.Vertical,androidx.compose.ui.Alignment.Horizontal,androidx.compose.foundation.gestures.FlingBehavior,kotlin.Boolean,androidx.compose.foundation.OverscrollEffect,kotlin.Function1)), which displays a list of strings.\n- `PullToRefreshBox` requires `isRefreshing` and `onRefresh` parameters.\n- The content within the `PullToRefreshBox` block represents the scrollable content.\n\nResult\n\nThis video demonstrates the basic pull-to-refresh implementation from\nthe preceding code:\n**Figure 1**. A basic pull-to-refresh implementation on a list of items.\n\nAdvanced example: Customize indicator color\n\n\n```kotlin\n@Composable\nfun PullToRefreshCustomStyleSample(\n items: List\u003cString\u003e,\n isRefreshing: Boolean,\n onRefresh: () -\u003e Unit,\n modifier: Modifier = Modifier\n) {\n val state = rememberPullToRefreshState()\n\n PullToRefreshBox(\n isRefreshing = isRefreshing,\n onRefresh = onRefresh,\n modifier = modifier,\n state = state,\n indicator = {\n Indicator(\n modifier = Modifier.align(Alignment.TopCenter),\n isRefreshing = isRefreshing,\n containerColor = MaterialTheme.colorScheme.primaryContainer,\n color = MaterialTheme.colorScheme.onPrimaryContainer,\n state = state\n )\n },\n ) {\n LazyColumn(Modifier.fillMaxSize()) {\n items(items) {\n ListItem({ Text(text = it) })\n }\n }\n }\n}https://github.com/android/snippets/blob/7a0ebbee11495f628cf9d574f6b6069c2867232a/compose/snippets/src/main/java/com/example/compose/snippets/components/PullToRefreshBox.kt#L115-L145\n```\n\n\u003cbr /\u003e\n\nKey points about the code\n\n- The indicator color is customized through the `containerColor` and `color` properties in the `indicator` parameter.\n- [`rememberPullToRefreshState()`](/reference/kotlin/androidx/compose/material3/pulltorefresh/PullToRefreshState) manages the state of the refresh action. You use this state in conjunction with the `indicator` parameter.\n\n| **Note:** In the basic example, `state` was not passed to `PullToRefreshBox` because it was using the default parameter value. However, in this example, you need to define the state, and pass that state to both the box and indicator to coordinate their behavior.\n\nResult\n\nThis video shows a pull-to-refresh implementation with a colored\nindicator:\n**Figure 2**. A pull-to-refresh implementation with a custom style.\n\nAdvanced example: Create a fully customized indicator\n\nYou can create complex custom indicators by leveraging existing composables and\nanimations.This snippet demonstrates how to create a fully custom indicator in\nyour pull-to-refresh implementation:\n\n\n```kotlin\n@Composable\nfun PullToRefreshCustomIndicatorSample(\n items: List\u003cString\u003e,\n isRefreshing: Boolean,\n onRefresh: () -\u003e Unit,\n modifier: Modifier = Modifier\n) {\n val state = rememberPullToRefreshState()\n\n PullToRefreshBox(\n isRefreshing = isRefreshing,\n onRefresh = onRefresh,\n modifier = modifier,\n state = state,\n indicator = {\n MyCustomIndicator(\n state = state,\n isRefreshing = isRefreshing,\n modifier = Modifier.align(Alignment.TopCenter)\n )\n }\n ) {\n LazyColumn(Modifier.fillMaxSize()) {\n items(items) {\n ListItem({ Text(text = it) })\n }\n }\n }\n}\n\n// ...\n@Composable\nfun MyCustomIndicator(\n state: PullToRefreshState,\n isRefreshing: Boolean,\n modifier: Modifier = Modifier,\n) {\n Box(\n modifier = modifier.pullToRefreshIndicator(\n state = state,\n isRefreshing = isRefreshing,\n containerColor = PullToRefreshDefaults.containerColor,\n threshold = PositionalThreshold\n ),\n contentAlignment = Alignment.Center\n ) {\n Crossfade(\n targetState = isRefreshing,\n animationSpec = tween(durationMillis = CROSSFADE_DURATION_MILLIS),\n modifier = Modifier.align(Alignment.Center)\n ) { refreshing -\u003e\n if (refreshing) {\n CircularProgressIndicator(Modifier.size(SPINNER_SIZE))\n } else {\n val distanceFraction = { state.distanceFraction.coerceIn(0f, 1f) }\n Icon(\n imageVector = Icons.Filled.CloudDownload,\n contentDescription = \"Refresh\",\n modifier = Modifier\n .size(18.dp)\n .graphicsLayer {\n val progress = distanceFraction()\n this.alpha = progress\n this.scaleX = progress\n this.scaleY = progress\n }\n )\n }\n }\n }\n}https://github.com/android/snippets/blob/7a0ebbee11495f628cf9d574f6b6069c2867232a/compose/snippets/src/main/java/com/example/compose/snippets/components/PullToRefreshBox.kt#L150-L222\n```\n\n\u003cbr /\u003e\n\nKey points about the code\n\n- The previous snippet used the `Indicator` provided by the library. This snippet creates a custom indicator composable called `MyCustomIndicator`. In this composable, the `pullToRefreshIndicator` modifier handles positioning and triggering a refresh.\n- As in the previous snippet, the example extracts the `PullToRefreshState` instance, so you can pass the same instance to both the `PullToRefreshBox` and the `pullToRefreshModifier`.\n- The example uses the container color and the position threshold from the `PullToRefreshDefaults` class. This way, you can reuse the default behavior and styling from the Material library, while customizing only the elements you're interested in.\n- `MyCustomIndicator` uses [`Crossfade`](/reference/kotlin/androidx/compose/animation/package-summary#Crossfade(kotlin.Any,androidx.compose.ui.Modifier,androidx.compose.animation.core.FiniteAnimationSpec,kotlin.String,kotlin.Function1)) to transition between a cloud icon and a `CircularProgressIndicator`. The cloud icon scales up as the user pulls, and transitions to a `CircularProgressIndicator` when the refresh action begins.\n - `targetState` uses `isRefreshing` to determine which state to display (the cloud icon or the circular progress indicator).\n - `animationSpec` defines a `tween` animation for the transition, with a specified duration of `CROSSFADE_DURATION_MILLIS`.\n - `state.distanceFraction` represents how far the user has pulled down, ranging from `0f` (no pull) to `1f` (fully pulled).\n - The `graphicsLayer` modifier modifies scale and transparency.\n\nResult\n\nThis video shows the custom indicator from the preceding code:\n**Figure 3**. A pull-to-refresh implementation with a custom indicator.\n\nAdditional resources\n\n- [`PullToRefreshState`](/reference/kotlin/androidx/compose/material3/pulltorefresh/PullToRefreshState)"]]