Pull to Refresh:接入 Expressive LoadingIndicator · AndroidX 源码指南
AAndroidX 源码指南
M3E 设计系统
M3E 设计系统 · androidx.compose.material3

Pull to Refresh:接入 Expressive LoadingIndicator1.5.0-alpha25

连接刷新状态、加载指示器和协程任务,避免只换指示器却忘记完整刷新数据流。

最后更新 2026-07-31

Expressive 改变的是 indicator

catalog 的 PullToRefreshWithLoadingIndicatorSample 使用新的 contained LoadingIndicator。刷新流程本身仍然是:用户下拉 → isRefreshing = true → 执行任务 → 更新内容 → false

PullToRefreshBox(
    isRefreshing = isRefreshing,
    onRefresh = { viewModel.refresh() },
    indicator = {
        PullToRefreshDefaults.LoadingIndicator(
            state = state,
            isRefreshing = isRefreshing,
        )
    },
) { Content() }

不要在 composable 中直接阻塞

官方 samples 通过 coroutine 执行刷新并在结束时复位状态。真实项目更适合让 ViewModel 暴露 refreshing 状态,避免旋转屏幕或重组时重复启动请求。

实验边界

PullToRefreshDefaults 中与 LoadingIndicator 对应的颜色和 composable 标记了 Expressive 实验 API;基础 PullToRefresh API 有自己的 Material3 experimental 边界,按编译器提示在最小范围 opt-in。

复制即用

带 Expressive LoadingIndicator 的下拉刷新:

import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.PullToRefreshBox
import androidx.compose.material3.PullToRefreshDefaults
import androidx.compose.material3.rememberPullToRefreshState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue

@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun RefreshableList(content: @Composable () -> Unit) {
    var isRefreshing by remember { mutableStateOf(false) }
    val state = rememberPullToRefreshState()

    PullToRefreshBox(
        isRefreshing = isRefreshing,
        onRefresh = {
            // 用协程执行刷新,结束后复位
        },
        indicator = {
            PullToRefreshDefaults.LoadingIndicator(
                state = state,
                isRefreshing = isRefreshing,
            )
        },
    ) {
        content()
    }
}

真实项目建议把刷新状态放进 ViewModel,避免重组或旋转屏幕时重复请求。