Interface

PullToRefreshState

The state of a PullToRefreshBox which tracks the distance that the container and indicator have been pulled.

PullToRefreshCustomIndicatorSample

@Sampled
@Composable
@Preview
fun PullToRefreshCustomIndicatorSample() {
    var isRefreshing by remember { mutableStateOf(false) }
    val coroutineScope = rememberCoroutineScope()
    val state = remember { PullToRefreshState() }
    val listState = rememberTransformingLazyColumnState()
    val transformationSpec = rememberTransformationSpec()

    AppScaffold {
        ScreenScaffold(scrollState = listState, timeText = { TimeText() }) { contentPadding ->
            PullToRefreshBox(
                isRefreshing = isRefreshing,
                onRefresh = {
                    isRefreshing = true
                    coroutineScope.launch {
                        delay(2000)
                        isRefreshing = false
                    }
                },
                state = state,
                indicator = {
                    PullToRefreshDefaults.IndicatorBox(
                        state = state,
                        isRefreshing = isRefreshing,
                        shape = MaterialTheme.shapes.medium,
                        containerColor = MaterialTheme.colorScheme.primaryContainer,
                        modifier = Modifier.align(Alignment.TopCenter),
                    ) {
                        if (isRefreshing) {
                            CircularProgressIndicator(
                                strokeWidth = 2.5.dp,
                                colors =
                                    ProgressIndicatorDefaults.colors(
                                        indicatorColor =
                                            MaterialTheme.colorScheme.onPrimaryContainer
                                    ),
                                modifier = Modifier.size(24.dp),
                            )
                        } else {
                            val rotation = state.distanceFraction * 180f
                            val scale = state.distanceFraction.coerceIn(0f, 1f)
                            Icon(
                                imageVector = Icons.Default.Refresh,
                                contentDescription = "Pull to refresh",
                                tint = MaterialTheme.colorScheme.onPrimaryContainer,
                                modifier =
                                    Modifier.size(24.dp).graphicsLayer {
                                        rotationZ = rotation
                                        scaleX = scale
                                        scaleY = scale
                                    },
                            )
                        }
                    }
                },
                modifier = Modifier.fillMaxSize(),
            ) {
                TransformingLazyColumn(
                    state = listState,
                    contentPadding = contentPadding,
                    modifier = Modifier.fillMaxSize(),
                ) {
                    items(10) { index ->
                        Button(
                            onClick = {},
                            label = { Text("Custom item ${index + 1}") },
                            transformation = SurfaceTransformation(transformationSpec),
                            modifier =
                                Modifier.transformedHeight(this, transformationSpec)
                                    .minimumVerticalContentPadding(
                                        ButtonDefaults.minimumVerticalListContentPadding
                                    )
                                    .fillMaxWidth(),
                        )
                    }
                }
            }
        }
    }
}
Jetpack Compose beyond MaterialFree components, screens and templates for apps that don’t look like Google’s. Copy them into your app, or let your coding agent add them.Browse for free

Content updated: