Jetpack Compose - Swipe to refresh

Swipe to refresh manually refreshes screen content with a user action or gesture.

This example demonstrates how to make a Jetpack Compose Custom Swipe to refresh


package compose.material.theme

import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.rememberScrollState
import androidx.compose.material.LinearProgressIndicator
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawWithCache
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import com.google.accompanist.swiperefresh.SwipeRefresh
import com.google.accompanist.swiperefresh.SwipeRefreshState
import com.google.accompanist.swiperefresh.rememberSwipeRefreshState
import compose.material.theme.ui.theme.Purple40
import compose.material.theme.ui.theme.Purple80
import kotlinx.coroutines.delay


@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SwipeToRefreshDemo(navController: NavController) {
val context = LocalContext.current
var isRefreshing by remember { mutableStateOf(false) }
val swipeRefreshState = rememberSwipeRefreshState(isRefreshing)


Scaffold(
topBar = {
CenterAlignedTopAppBar(
title = { Text("Swipe to refresh") },
Modifier.background(Purple40),
navigationIcon = {
IconButton(onClick = { /* doSomething() */
navController.navigateUp()
}) {
Icon(
imageVector = Icons.Filled.ArrowBack,
contentDescription = "Localized description"
)
}
},
)
},
content = {

Column {
SwipeRefresh(
state = swipeRefreshState,
onRefresh = {
isRefreshing = true
},
indicator = { state, trigger ->
CustomViewPullRefreshView(state, trigger)
}
) {


// body content
val scrollState = rememberScrollState()
BlogContentSimple(scrollState)

// 2 sec delay
LaunchedEffect(isRefreshing) {
if (isRefreshing) {
delay(2000L)
isRefreshing = false
}
}
}
}


}
)

}

@Composable
fun CustomViewPullRefreshView(
swipeRefreshState: SwipeRefreshState,
refreshTriggerDistance: Dp,
color: Color = Purple80
) {
Box(
Modifier
.drawWithCache {
onDrawBehind {
val distance = refreshTriggerDistance.toPx()
val progress = (swipeRefreshState.indicatorOffset / distance).coerceIn(0f, 1f)
val brush = Brush.verticalGradient(
0f to color.copy(alpha = 0.45f),
1f to color.copy(alpha = 0f)
)
drawRect(
brush = brush,
alpha = FastOutSlowInEasing.transform(progress)
)
}
}
.fillMaxWidth()
.height(80.dp)
) {
if (swipeRefreshState.isRefreshing) {
LinearProgressIndicator(
Modifier.fillMaxWidth(),
color = Purple80
)
} else {
val trigger = with(LocalDensity.current) { refreshTriggerDistance.toPx() }
val progress = (swipeRefreshState.indicatorOffset / trigger).coerceIn(0f, 1f)
LinearProgressIndicator(
progress = progress,
modifier = Modifier.fillMaxWidth(),
color = Purple40
)
}
}
}



Accompanist SwipeRefresh library 
Utilities for Jetpack Compose : 
   implementation "com.google.accompanist:accompanist-swiperefresh:0.22.0-rc"

..

Comments