Class

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(),
                        )
                    }
                }
            }
        }
    }
}

Content updated: