PullToRefreshState

class PullToRefreshState


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

Each instance of PullToRefreshBox should have its own PullToRefreshState.

PullToRefreshState can be used with custom progress indicators like so:

import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.unit.dp
import androidx.wear.compose.foundation.lazy.TransformingLazyColumn
import androidx.wear.compose.foundation.lazy.rememberTransformingLazyColumnState
import androidx.wear.compose.material3.AppScaffold
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.ButtonDefaults
import androidx.wear.compose.material3.CircularProgressIndicator
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.MaterialTheme
import androidx.wear.compose.material3.ProgressIndicatorDefaults
import androidx.wear.compose.material3.PullToRefreshBox
import androidx.wear.compose.material3.PullToRefreshDefaults
import androidx.wear.compose.material3.PullToRefreshState
import androidx.wear.compose.material3.ScreenScaffold
import androidx.wear.compose.material3.SurfaceTransformation
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.TimeText
import androidx.wear.compose.material3.lazy.rememberTransformationSpec
import androidx.wear.compose.material3.lazy.transformedHeight

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

Summary

Public functions

suspend Unit

Animate the distance towards the position where the indicator will be hidden when idle.

suspend Unit

Animate the distance towards the anchor or threshold position, where the indicator will be shown when refreshing.

suspend Unit
snapTo(targetValue: @FloatRange(from = 0.0) Float)

Snap the indicator to the desired threshold fraction.

Public properties

Float

Distance percentage towards the refresh threshold.

Boolean

Whether the state is currently animating the indicator to the threshold offset, or back to the hidden offset.

Public constructors

Public functions

animateToHidden

Added in 1.8.0-alpha01
suspend fun animateToHidden(animationSpec: AnimationSpec<Float> = spring()): Unit

Animate the distance towards the position where the indicator will be hidden when idle.

Parameters
animationSpec: AnimationSpec<Float> = spring()

The AnimationSpec used for animating the distance.

animateToThreshold

Added in 1.8.0-alpha01
suspend fun animateToThreshold(animationSpec: AnimationSpec<Float> = spring()): Unit

Animate the distance towards the anchor or threshold position, where the indicator will be shown when refreshing.

Parameters
animationSpec: AnimationSpec<Float> = spring()

The AnimationSpec used for animating the distance.

snapTo

Added in 1.8.0-alpha01
suspend fun snapTo(targetValue: @FloatRange(from = 0.0) Float): Unit

Snap the indicator to the desired threshold fraction.

Parameters
targetValue: @FloatRange(from = 0.0) Float

The target fraction to snap to, where 0.0 represents the hidden state and 1.0 represents the threshold position.

Public properties

distanceFraction

Added in 1.8.0-alpha01
val distanceFraction: Float

Distance percentage towards the refresh threshold. 0.0 indicates no distance, 1.0 indicates being at the threshold offset, > 1.0 indicates overshoot beyond the provided threshold.

isAnimating

Added in 1.8.0-alpha01
val isAnimating: Boolean

Whether the state is currently animating the indicator to the threshold offset, or back to the hidden offset.