# PullToRefreshBox

## Functions summary

|---|---|
| `https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/index.html` | `@https://developer.android.com/reference/kotlin/androidx/compose/runtime/Composable https://developer.android.com/reference/kotlin/androidx/wear/compose/material3/PullToRefreshBox.composable#PullToRefreshBox(kotlin.Boolean,kotlin.Function0,androidx.wear.compose.material3.PullToRefreshState,androidx.compose.ui.Modifier,androidx.compose.ui.Alignment,kotlin.Function1,kotlin.Boolean,androidx.compose.ui.unit.Dp,kotlin.Function1)( isRefreshing: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-boolean/index.html, onRefresh: () -> https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/index.html, state: https://developer.android.com/reference/kotlin/androidx/wear/compose/material3/PullToRefreshState, modifier: https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier, contentAlignment: https://developer.android.com/reference/kotlin/androidx/compose/ui/Alignment, indicator: @https://developer.android.com/reference/kotlin/androidx/compose/runtime/Composable https://developer.android.com/reference/kotlin/androidx/compose/foundation/layout/BoxScope.() -> https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/index.html, enabled: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-boolean/index.html, threshold: https://developer.android.com/reference/kotlin/androidx/compose/ui/unit/Dp, content: @https://developer.android.com/reference/kotlin/androidx/compose/runtime/Composable https://developer.android.com/reference/kotlin/androidx/compose/foundation/layout/BoxScope.() -> https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/index.html )` Container that wraps scrollable content to add pull-to-refresh gesture support. |

## Functions

### PullToRefreshBox

Artifact: [androidx.wear.compose:compose-material3](https://developer.android.com/jetpack/androidx/releases/wear-compose) [View Source](https://cs.android.com/search?q=file:androidx/wear/compose/material3/PullToRefresh.kt+function:PullToRefreshBox)

```
@Composable
fun PullToRefreshBox(
    isRefreshing: Boolean,
    onRefresh: () -> Unit,
    state: PullToRefreshState,
    modifier: Modifier = Modifier,
    contentAlignment: Alignment = Alignment.TopCenter,
    indicator: @Composable BoxScope.() -> Unit = {
        PullToRefreshDefaults.Indicator(
            modifier = Modifier.align(Alignment.TopCenter),
            isRefreshing = isRefreshing,
            state = state,
        )
    },
    enabled: Boolean = true,
    threshold: Dp = PullToRefreshDefaults.PositionalThreshold,
    content: @Composable BoxScope.() -> Unit
): Unit
```

Container that wraps scrollable content to add pull-to-refresh gesture support.

By default, it uses `https://developer.android.com/reference/kotlin/androidx/wear/compose/material3/PullToRefreshDefaults#Indicator(androidx.wear.compose.material3.PullToRefreshState,kotlin.Boolean,androidx.compose.ui.Modifier,androidx.compose.ui.graphics.Color,androidx.wear.compose.material3.ProgressIndicatorColors,androidx.compose.ui.unit.Dp)` as the refresh indicator, which internally uses a `https://developer.android.com/reference/kotlin/androidx/wear/compose/material3/CircularProgressIndicator.composable#CircularProgressIndicator(kotlin.Function0,androidx.compose.ui.Modifier,kotlin.Boolean,kotlin.Boolean,kotlin.Float,kotlin.Float,androidx.wear.compose.material3.ProgressIndicatorColors,androidx.compose.ui.unit.Dp,androidx.compose.ui.unit.Dp)` when refreshing. You may also choose to set your own indicator.

Example of a standard `https://developer.android.com/reference/kotlin/androidx/wear/compose/material3/PullToRefreshBox.composable#PullToRefreshBox(kotlin.Boolean,kotlin.Function0,androidx.wear.compose.material3.PullToRefreshState,androidx.compose.ui.Modifier,androidx.compose.ui.Alignment,kotlin.Function1,kotlin.Boolean,androidx.compose.ui.unit.Dp,kotlin.Function1)` wrapping a `https://developer.android.com/reference/kotlin/androidx/wear/compose/foundation/lazy/TransformingLazyColumn.composable#TransformingLazyColumn(androidx.compose.ui.Modifier,androidx.wear.compose.foundation.lazy.TransformingLazyColumnState,androidx.compose.foundation.layout.PaddingValues,kotlin.Boolean,androidx.compose.foundation.layout.Arrangement.Vertical,androidx.compose.ui.Alignment.Horizontal,androidx.compose.foundation.gestures.FlingBehavior,kotlin.Boolean,androidx.wear.compose.foundation.rotary.RotaryScrollableBehavior,androidx.compose.foundation.OverscrollEffect,androidx.wear.compose.foundation.lazy.TransformingLazyColumnFirstLayoutItemProvider,kotlin.Function1)`:

```kotlin
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
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.PullToRefreshBox
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 itemCount by remember { mutableIntStateOf(10) }
var isRefreshing by remember { mutableStateOf(false) }
val coroutineScope = rememberCoroutineScope()
val listState = rememberTransformingLazyColumnState()
val transformationSpec = rememberTransformationSpec()
val state = remember { PullToRefreshState() }

AppScaffold {
    ScreenScaffold(scrollState = listState, timeText = { TimeText() }) { contentPadding ->
        PullToRefreshBox(
            isRefreshing = isRefreshing,
            onRefresh = {
                isRefreshing = true
                coroutineScope.launch {
                    delay(2000)
                    itemCount += 5
                    isRefreshing = false
                }
            },
            state = state,
            modifier = Modifier.fillMaxSize(),
        ) {
            TransformingLazyColumn(
                state = listState,
                contentPadding = contentPadding,
                modifier = Modifier.fillMaxSize(),
            ) {
                items(itemCount) { index ->
                    Button(
                        onClick = {},
                        label = { Text("Item ${index + 1}") },
                        transformation = SurfaceTransformation(transformationSpec),
                        modifier =
                            Modifier.transformedHeight(this, transformationSpec)
                                .minimumVerticalContentPadding(
                                    ButtonDefaults.minimumVerticalListContentPadding
                                )
                                .fillMaxWidth(),
                    )
                }
            }
        }
    }
}
```

Example of a `https://developer.android.com/reference/kotlin/androidx/wear/compose/material3/PullToRefreshBox.composable#PullToRefreshBox(kotlin.Boolean,kotlin.Function0,androidx.wear.compose.material3.PullToRefreshState,androidx.compose.ui.Modifier,androidx.compose.ui.Alignment,kotlin.Function1,kotlin.Boolean,androidx.compose.ui.unit.Dp,kotlin.Function1)` with a custom indicator:

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

| Parameters |
|---|---|
| `isRefreshing: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-boolean/index.html` | whether a refresh is occurring |
| `onRefresh: () -> https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/index.html` | callback invoked when the user gesture crosses the threshold, thereby requesting a refresh. |
| `state: https://developer.android.com/reference/kotlin/androidx/wear/compose/material3/PullToRefreshState` | the state that keeps track of distance pulled |
| `modifier: https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier = Modifier` | the `https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier` to be applied to this container |
| `contentAlignment: https://developer.android.com/reference/kotlin/androidx/compose/ui/Alignment = Alignment.TopCenter` | the default alignment inside the Box. |
| `indicator: @https://developer.android.com/reference/kotlin/androidx/compose/runtime/Composable https://developer.android.com/reference/kotlin/androidx/compose/foundation/layout/BoxScope.() -> https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/index.html = { PullToRefreshDefaults.Indicator( modifier = Modifier.align(Alignment.TopCenter), isRefreshing = isRefreshing, state = state, ) }` | the indicator that will be drawn on top of the content when the user begins a pull or a refresh is occurring |
| `enabled: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-boolean/index.html = true` | whether nested scroll events should be consumed by this component |
| `threshold: https://developer.android.com/reference/kotlin/androidx/compose/ui/unit/Dp = PullToRefreshDefaults.PositionalThreshold` | how much distance can be scrolled down before `https://developer.android.com/reference/kotlin/androidx/wear/compose/material3/package-summary#PullToRefreshBox(kotlin.Boolean,kotlin.Function0,androidx.wear.compose.material3.PullToRefreshState,androidx.compose.ui.Modifier,androidx.compose.ui.Alignment,kotlin.Function1,kotlin.Boolean,androidx.compose.ui.unit.Dp,kotlin.Function1)` is invoked |
| `content: @https://developer.android.com/reference/kotlin/androidx/compose/runtime/Composable https://developer.android.com/reference/kotlin/androidx/compose/foundation/layout/BoxScope.() -> https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/index.html` | the content of the pull refresh container, typically a scrollable layout such as `https://developer.android.com/reference/kotlin/androidx/wear/compose/foundation/lazy/TransformingLazyColumn.composable#TransformingLazyColumn(androidx.compose.ui.Modifier,androidx.wear.compose.foundation.lazy.TransformingLazyColumnState,androidx.compose.foundation.layout.PaddingValues,kotlin.Boolean,androidx.compose.foundation.layout.Arrangement.Vertical,androidx.compose.ui.Alignment.Horizontal,androidx.compose.foundation.gestures.FlingBehavior,kotlin.Boolean,androidx.wear.compose.foundation.rotary.RotaryScrollableBehavior,androidx.compose.foundation.OverscrollEffect,androidx.wear.compose.foundation.lazy.TransformingLazyColumnFirstLayoutItemProvider,kotlin.Function1)` or a layout using `https://developer.android.com/reference/kotlin/androidx/compose/foundation/verticalScroll.modifier#(androidx.compose.ui.Modifier).verticalScroll(androidx.compose.foundation.ScrollState,kotlin.Boolean,androidx.compose.foundation.gestures.FlingBehavior,kotlin.Boolean)` |