Lucas Kivi
10/02/2024, 6:26 PMtargetPage
should be the way to do it, but it takes a non-deterministic amount of time to update after being dropped. 😬 Additionally, it updates before the user stops dragging. I only want the updates when the user let’s go of the page.
Code and demo in the thread. 🧵Lucas Kivi
10/02/2024, 6:26 PM@Composable
private fun PagerTestScreen(
modifier: Modifier = Modifier,
) {
val pages = remember { List(10) { it } }
val pagerState = rememberPagerState { pages.size }
var dragCancellationPage by remember { mutableIntStateOf(pagerState.currentPage) }
var dragCancellationPageWithDelay by remember { mutableIntStateOf(pagerState.currentPage) }
LaunchedEffect(pagerState) {
pagerState
.interactionSource
.collectLatestDragCancellation {
dragCancellationPage = pagerState.targetPage
}
}
LaunchedEffect(pagerState) {
pagerState
.interactionSource
.collectLatestDragCancellation {
delay(50)
dragCancellationPageWithDelay = pagerState.targetPage
}
}
val textModifier = Modifier
.padding(16.dp)
.background(Color.Gray)
.padding(16.dp)
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
modifier = modifier,
) {
Text(
text = "Target Page: ${pagerState.targetPage}",
modifier = textModifier,
)
Text(
text = "Dragged cancellation page: $dragCancellationPage",
modifier = textModifier,
)
Text(
text = "Dragged cancellation page with delay: $dragCancellationPageWithDelay",
modifier = textModifier,
)
HorizontalPager(
contentPadding = PaddingValues(24.dp),
pageSpacing = 16.dp,
pageSize = PageSize.Fill,
state = pagerState,
) { index ->
Page(
pageNumber = pages[index],
modifier = Modifier.fillMaxWidth(),
)
}
}
}
@Composable
private fun Page(
pageNumber: Int,
modifier: Modifier = Modifier,
) {
Box(
contentAlignment = Alignment.Center,
modifier = modifier
.background(
color = Color.White,
shape = RoundedCornerShape(8.dp),
)
.height(64.dp),
) {
Text(
text = pageNumber.toString(),
)
}
}
}
/**
* If there is a drag action on this [InteractionSource], when it stops or is canceled, this function will invoke
* [block]. When a new drag action comes in, the flow returned by [block] will be cancelled.
*
* This is useful for performing work when a draggable component is done being dragged.
*/
private suspend fun InteractionSource.collectLatestDragCancellation(
block: suspend () -> Unit,
) {
this
.interactions
.collect {
when (it) {
is DragInteraction.Stop,
is DragInteraction.Cancel,
-> block()
}
}
}
Lucas Kivi
10/02/2024, 6:26 PMLucas Kivi
10/02/2024, 6:28 PM