xref: /aosp_15_r20/external/accompanist/docs/swiperefresh.md (revision fa44fe6ae8e729aa3cfe5c03eedbbf98fb44e2c6)
1*fa44fe6aSInna Palant# Swipe Refresh for Jetpack Compose
2*fa44fe6aSInna Palant
3*fa44fe6aSInna Palant[![Maven Central](https://img.shields.io/maven-central/v/com.google.accompanist/accompanist-swiperefresh)](https://search.maven.org/search?q=g:com.google.accompanist)
4*fa44fe6aSInna Palant
5*fa44fe6aSInna Palant!!! warning
6*fa44fe6aSInna Palant    **This library is deprecated, with official pull refresh support in [androidx.compose.material.pullrefresh](https://developer.android.com/reference/kotlin/androidx/compose/material/pullrefresh/package-summary).** The migration guide and original documentation is below.
7*fa44fe6aSInna Palant
8*fa44fe6aSInna Palant## Migration
9*fa44fe6aSInna Palant
10*fa44fe6aSInna PalantAccompanist SwipeRefresh has been replaced by PullRefresh in [Compose Material 1.3.0](https://developer.android.com/jetpack/androidx/releases/compose-material#1.3.0). The implementation is similar but instead of being a Composable function, it is a Modifier that can be applied to a Composable function.
11*fa44fe6aSInna Palant
12*fa44fe6aSInna PalantA simple example is as follows:
13*fa44fe6aSInna Palant
14*fa44fe6aSInna Palant```kotlin
15*fa44fe6aSInna Palantval viewModel: MyViewModel = viewModel()
16*fa44fe6aSInna Palantval refreshing by viewModel.isRefreshing
17*fa44fe6aSInna Palant
18*fa44fe6aSInna Palantval pullRefreshState = rememberPullRefreshState(refreshing, { viewModel.refresh() })
19*fa44fe6aSInna Palant
20*fa44fe6aSInna PalantBox(Modifier.pullRefresh(pullRefreshState)) {
21*fa44fe6aSInna Palant    LazyColumn(Modifier.fillMaxSize()) {
22*fa44fe6aSInna Palant        ...
23*fa44fe6aSInna Palant    }
24*fa44fe6aSInna Palant
25*fa44fe6aSInna Palant    PullRefreshIndicator(refreshing, pullRefreshState, Modifier.align(Alignment.TopCenter))
26*fa44fe6aSInna Palant}
27*fa44fe6aSInna Palant```
28*fa44fe6aSInna Palant
29*fa44fe6aSInna Palant### Migration steps
30*fa44fe6aSInna Palant
31*fa44fe6aSInna Palant1. Replace SwipeRefresh with a Box or other layout of your choice, save your `onRefresh` lambda for the next step.
32*fa44fe6aSInna Palant2. Replace `rememberSwipeRefreshState()` with `rememberPullRefreshState(refreshing, onRefresh)`
33*fa44fe6aSInna Palant3. Add either the default `PullRefreshIndicator` or your own custom implementation to your layout.
34*fa44fe6aSInna Palant
35*fa44fe6aSInna Palant### Custom Indicator
36*fa44fe6aSInna Palant
37*fa44fe6aSInna PalantInstead of using the provided `PullRefreshIndicator` composable, you can create your own custom indicator.
38*fa44fe6aSInna PalantA full sample can be seen in the [Compose samples](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/material/material/samples/src/main/java/androidx/compose/material/samples/PullRefreshSamples.kt;l=91?q=pullrefresh).
39*fa44fe6aSInna Palant
40*fa44fe6aSInna Palant## Original Docs
41*fa44fe6aSInna Palant
42*fa44fe6aSInna PalantA library which provides a layout which provides the swipe-to-refresh UX pattern, similar to Android's [`SwipeRefreshLayout`](https://developer.android.com/training/swipe/add-swipe-interface).
43*fa44fe6aSInna Palant
44*fa44fe6aSInna Palant<figure>
45*fa44fe6aSInna Palant    <video width="400" controls loop>
46*fa44fe6aSInna Palant    <source src="demo.mp4" type="video/mp4">
47*fa44fe6aSInna Palant        Your browser does not support the video tag.
48*fa44fe6aSInna Palant    </video>
49*fa44fe6aSInna Palant    <figcaption>SwipeRefresh demo</figcaption>
50*fa44fe6aSInna Palant</figure>
51*fa44fe6aSInna Palant
52*fa44fe6aSInna Palant## Usage
53*fa44fe6aSInna Palant
54*fa44fe6aSInna PalantTo implement this UX pattern there are two key APIs which are needed: [`SwipeRefresh`][api_swiperefresh], which is provides the layout, and [`rememberSwipeRefreshState()`][api_rememberstate] which provides some remembered state.
55*fa44fe6aSInna Palant
56*fa44fe6aSInna PalantThe basic usage of a [`SwipeRefresh`][api_swiperefresh] using a ViewModel looks like so:
57*fa44fe6aSInna Palant
58*fa44fe6aSInna Palant``` kotlin
59*fa44fe6aSInna Palantval viewModel: MyViewModel = viewModel()
60*fa44fe6aSInna Palantval isRefreshing by viewModel.isRefreshing.collectAsState()
61*fa44fe6aSInna Palant
62*fa44fe6aSInna PalantSwipeRefresh(
63*fa44fe6aSInna Palant    state = rememberSwipeRefreshState(isRefreshing),
64*fa44fe6aSInna Palant    onRefresh = { viewModel.refresh() },
65*fa44fe6aSInna Palant) {
66*fa44fe6aSInna Palant    LazyColumn {
67*fa44fe6aSInna Palant        items(30) { index ->
68*fa44fe6aSInna Palant            // TODO: list items
69*fa44fe6aSInna Palant        }
70*fa44fe6aSInna Palant    }
71*fa44fe6aSInna Palant}
72*fa44fe6aSInna Palant```
73*fa44fe6aSInna Palant
74*fa44fe6aSInna PalantThe full example, including the view model implementation can be found [here](https://github.com/google/accompanist/blob/main/sample/src/main/java/com/google/accompanist/sample/swiperefresh/DocsSamples.kt).
75*fa44fe6aSInna Palant
76*fa44fe6aSInna PalantThe content needs to be 'vertically scrollable' for `SwipeRefresh()` to be able to react to swipe gestures. Layouts such as [`LazyColumn`][lazycolumn] are automatically vertically scrollable, but others such as [`Column`][column] or [`LazyRow`][lazyrow] are not. In those instances, you can provide a [`Modifier.verticalScroll`][verticalscroll] modifier to that content like so:
77*fa44fe6aSInna Palant
78*fa44fe6aSInna Palant``` kotlin
79*fa44fe6aSInna PalantSwipeRefresh(
80*fa44fe6aSInna Palant    // ...
81*fa44fe6aSInna Palant) {
82*fa44fe6aSInna Palant    Column(Modifier.verticalScroll(rememberScrollState())) {
83*fa44fe6aSInna Palant        // content
84*fa44fe6aSInna Palant    }
85*fa44fe6aSInna Palant}
86*fa44fe6aSInna Palant```
87*fa44fe6aSInna Palant
88*fa44fe6aSInna Palant
89*fa44fe6aSInna Palant### Indicating a refresh without swiping
90*fa44fe6aSInna Palant
91*fa44fe6aSInna PalantAs this library is built with a separate state object, it's easy to display a refreshing indicator without a swipe to triggering it.
92*fa44fe6aSInna Palant
93*fa44fe6aSInna PalantThe unrealistic example below displays a forever refreshing indicator:
94*fa44fe6aSInna Palant
95*fa44fe6aSInna Palant``` kotlin
96*fa44fe6aSInna Palantval swipeRefreshState = rememberSwipeRefreshState(true)
97*fa44fe6aSInna Palant
98*fa44fe6aSInna PalantSwipeRefresh(
99*fa44fe6aSInna Palant    state = swipeRefreshState,
100*fa44fe6aSInna Palant    onRefresh = { /* todo */ },
101*fa44fe6aSInna Palant) {
102*fa44fe6aSInna Palant    LazyColumn {
103*fa44fe6aSInna Palant        items(30) { index ->
104*fa44fe6aSInna Palant            // TODO: list items
105*fa44fe6aSInna Palant        }
106*fa44fe6aSInna Palant    }
107*fa44fe6aSInna Palant}
108*fa44fe6aSInna Palant```
109*fa44fe6aSInna Palant
110*fa44fe6aSInna Palant## Indicator
111*fa44fe6aSInna Palant
112*fa44fe6aSInna PalantThe library provides a default indicator: [`SwipeRefreshIndicator()`][api_swiperefreshindicator], which `SwipeRefresh` uses automatically. You can customize the default indicator, and even provide your own indicator content using the `indicator` slot.
113*fa44fe6aSInna Palant
114*fa44fe6aSInna Palant### Customizing default indicator
115*fa44fe6aSInna Palant
116*fa44fe6aSInna PalantTo customize the default indicator, we can provide our own `indicator` content block, to call [`SwipeRefreshIndicator()`][api_swiperefreshindicator] with customized parameters:
117*fa44fe6aSInna Palant
118*fa44fe6aSInna Palant=== "Sample"
119*fa44fe6aSInna Palant
120*fa44fe6aSInna Palant    ``` kotlin
121*fa44fe6aSInna Palant    SwipeRefresh(
122*fa44fe6aSInna Palant        state = /* ... */,
123*fa44fe6aSInna Palant        onRefresh = /* ... */,
124*fa44fe6aSInna Palant        indicator = { state, trigger ->
125*fa44fe6aSInna Palant            SwipeRefreshIndicator(
126*fa44fe6aSInna Palant                // Pass the SwipeRefreshState + trigger through
127*fa44fe6aSInna Palant                state = state,
128*fa44fe6aSInna Palant                refreshTriggerDistance = trigger,
129*fa44fe6aSInna Palant                // Enable the scale animation
130*fa44fe6aSInna Palant                scale = true,
131*fa44fe6aSInna Palant                // Change the color and shape
132*fa44fe6aSInna Palant                backgroundColor = MaterialTheme.colors.primary,
133*fa44fe6aSInna Palant                shape = MaterialTheme.shapes.small,
134*fa44fe6aSInna Palant            )
135*fa44fe6aSInna Palant        }
136*fa44fe6aSInna Palant    )
137*fa44fe6aSInna Palant    ```
138*fa44fe6aSInna Palant
139*fa44fe6aSInna Palant=== "Demo video"
140*fa44fe6aSInna Palant
141*fa44fe6aSInna Palant    <figure>
142*fa44fe6aSInna Palant        <video width="480" controls loop>
143*fa44fe6aSInna Palant        <source src="tweaked.mp4" type="video/mp4">
144*fa44fe6aSInna Palant            Your browser does not support the video tag.
145*fa44fe6aSInna Palant        </video>
146*fa44fe6aSInna Palant        <figcaption>Tweaked indicator demo</figcaption>
147*fa44fe6aSInna Palant    </figure>
148*fa44fe6aSInna Palant
149*fa44fe6aSInna Palant### Custom indicator
150*fa44fe6aSInna Palant
151*fa44fe6aSInna PalantAs mentioned, you can also provide your own custom indicator content. A [`SwipeRefreshState`][api_swiperefreshstate] is provided to `indicator` content slot, which contains the information necessary to react to a swipe refresh gesture.
152*fa44fe6aSInna Palant
153*fa44fe6aSInna PalantAn example of a custom indicator is provided [here][sample_customindicator].
154*fa44fe6aSInna Palant
155*fa44fe6aSInna Palant## Download
156*fa44fe6aSInna Palant
157*fa44fe6aSInna Palant[![Maven Central](https://img.shields.io/maven-central/v/com.google.accompanist/accompanist-swiperefresh)](https://search.maven.org/search?q=g:com.google.accompanist)
158*fa44fe6aSInna Palant
159*fa44fe6aSInna Palant```groovy
160*fa44fe6aSInna Palantrepositories {
161*fa44fe6aSInna Palant    mavenCentral()
162*fa44fe6aSInna Palant}
163*fa44fe6aSInna Palant
164*fa44fe6aSInna Palantdependencies {
165*fa44fe6aSInna Palant    implementation "com.google.accompanist:accompanist-swiperefresh:<version>"
166*fa44fe6aSInna Palant}
167*fa44fe6aSInna Palant```
168*fa44fe6aSInna Palant
169*fa44fe6aSInna PalantSnapshots of the development version are available in [Sonatype's `snapshots` repository][snap]. These are updated on every commit.
170*fa44fe6aSInna Palant
171*fa44fe6aSInna Palant  [compose]: https://developer.android.com/jetpack/compose
172*fa44fe6aSInna Palant  [snap]: https://oss.sonatype.org/content/repositories/snapshots/com/google/accompanist/accompanist-swiperefresh/
173*fa44fe6aSInna Palant  [api_swiperefreshstate]: ../api/swiperefresh/com.google.accompanist.swiperefresh/-swipe-refresh-state/
174*fa44fe6aSInna Palant  [api_swiperefreshindicator]: ../api/swiperefresh/com.google.accompanist.swiperefresh/-swipe-refresh-indicator.html
175*fa44fe6aSInna Palant  [api_swiperefresh]: ../api/swiperefresh/com.google.accompanist.swiperefresh/-swipe-refresh.html
176*fa44fe6aSInna Palant  [api_rememberstate]: ../api/swiperefresh/com.google.accompanist.swiperefresh/remember-swipe-refresh-state.html
177*fa44fe6aSInna Palant  [sample_customindicator]: https://github.com/google/accompanist/blob/main/sample/src/main/java/com/google/accompanist/sample/swiperefresh/SwipeRefreshCustomIndicatorSample.kt
178*fa44fe6aSInna Palant  [lazycolumn]: https://developer.android.com/reference/kotlin/androidx/compose/foundation/lazy/package-summary#LazyColumn(androidx.compose.ui.Modifier,androidx.compose.foundation.lazy.LazyListState,androidx.compose.foundation.layout.PaddingValues,kotlin.Boolean,androidx.compose.foundation.layout.Arrangement.Vertical,androidx.compose.ui.Alignment.Horizontal,androidx.compose.foundation.gestures.FlingBehavior,kotlin.Function1)
179*fa44fe6aSInna Palant  [column]: https://developer.android.com/reference/kotlin/androidx/compose/foundation/layout/package-summary#Column(androidx.compose.ui.Modifier,androidx.compose.foundation.layout.Arrangement.Vertical,androidx.compose.ui.Alignment.Horizontal,kotlin.Function1)
180*fa44fe6aSInna Palant  [lazyrow]: https://developer.android.com/reference/kotlin/androidx/compose/foundation/lazy/package-summary#LazyRow(androidx.compose.ui.Modifier,androidx.compose.foundation.lazy.LazyListState,androidx.compose.foundation.layout.PaddingValues,kotlin.Boolean,androidx.compose.foundation.layout.Arrangement.Horizontal,androidx.compose.ui.Alignment.Vertical,androidx.compose.foundation.gestures.FlingBehavior,kotlin.Function1)
181*fa44fe6aSInna Palant  [verticalscroll]: https://developer.android.com/jetpack/compose/gestures#scroll-modifiers
182