pullRefreshIndicatorTransform

Compose Modifier

Common
@ExperimentalMaterialApi
fun Modifier.pullRefreshIndicatorTransform(state: PullRefreshState, scale: Boolean = false) =
    drawWithContent {
            clipRect(
                top = 0f,
                left = -Float.MAX_VALUE,
                right = Float.MAX_VALUE,
                bottom = Float.MAX_VALUE,
            ) {
                this@drawWithContent.drawContent()
            }
        }
        .graphicsLayer {
            translationY = state.position - size.height

            if (scale && !state.refreshing) {
                val scaleFraction =
                    LinearOutSlowInEasing.transform(state.position / state.threshold)
                        .fastCoerceIn(0f, 1f)
                scaleX = scaleFraction
                scaleY = scaleFraction
            }
        }

A modifier for translating the position and scaling the size of a pull-to-refresh indicator based on the given PullRefreshState.

Parameters

stateThe PullRefreshState which determines the position of the indicator.
scaleA boolean controlling whether the indicator's size scales with pull progress or not.

Code Examples

PullRefreshIndicatorTransformSample

/**
 * An example to show how [pullRefreshIndicatorTransform] can be given custom contents to create a
 * custom indicator.
 */
@Composable
@OptIn(ExperimentalMaterialApi::class)
fun PullRefreshIndicatorTransformSample() {
    val refreshScope = rememberCoroutineScope()
    var refreshing by remember { mutableStateOf(false) }
    var itemCount by remember { mutableStateOf(15) }
    fun refresh() =
        refreshScope.launch {
            refreshing = true
            delay(1500)
            itemCount += 5
            refreshing = false
        }
    val state = rememberPullRefreshState(refreshing, ::refresh)
    val rotation = animateFloatAsState(state.progress * 120)
    Box(Modifier.fillMaxSize().pullRefresh(state)) {
        LazyColumn {
            if (!refreshing) {
                items(itemCount) { ListItem { Text(text = "Item ${itemCount - it}") } }
            }
        }
        Surface(
            modifier =
                Modifier.size(40.dp)
                    .align(Alignment.TopCenter)
                    .pullRefreshIndicatorTransform(state)
                    .rotate(rotation.value),
            shape = RoundedCornerShape(10.dp),
            color = Color.DarkGray,
            elevation = if (state.progress > 0 || refreshing) 20.dp else 0.dp,
        ) {
            Box {
                if (refreshing) {
                    CircularProgressIndicator(
                        modifier = Modifier.align(Alignment.Center).size(25.dp),
                        color = Color.White,
                        strokeWidth = 3.dp,
                    )
                }
            }
        }
    }
}