Reputation: 152
Helo folks I am facing this issue on which i need little bit of clearance,
I m trying to implement Horizontal progress basically same as in instagram stories
thing is when user starts scrolling to another story or long presses the story i want to Pause my progressbar animation. I have implemented my progress bar following way
fun HorizontalProgressBar(
modifier: Modifier = Modifier,
progressColor: Color = Color.White,
backGroundColor: Color = Color.White.copy(0.14f),
progressBarsState: ProgressBarsState = ProgressBarsState.NOT_STARTED,
index: Int = 0,
paused: Boolean = false,
onSliceFinished: () -> Unit,
) {
val initialValue = when (progressBarsState) {
ProgressBarsState.COMPLETED -> 1f
else -> 0f
}
var progress by remember {
mutableStateOf(initialValue)
}
//using coroutine to increase progress value for animation purpose
LaunchedEffect( key1 = paused) {
if (paused){
cancel()
} else {
if (progressBarsState == ProgressBarsState.PLAYING) {
while (progress < 1f) {
progress += 0.01f
delay(20)
}
onSliceFinished()
}
}
}
LinearProgressIndicator(
progress = progress,
modifier
.height(2.dp)
.clip(YouthAppTheme.shapes.medium),
progressColor,
backGroundColor
)
}
and then from the outside i have pagerState field isScrollInProgress as a compose state so that user starts scrolling pager I would recompose this function with changed paused parameter,
var scrollInProgress by remember {
mutableStateOf(pagerState.isScrollInProgress)
}
SlicedProgressBar(
2,
modifier = Modifier
.fillMaxWidth()
.height(48.dp),
paused = scrollInProgress,
spacing = 10.dp
)
SlicedProgressBar is basically many progressBars together same as it is in instagram stories
@Composable
fun SlicedProgressBar(
pageCount: Int,
modifier: Modifier,
paused: Boolean,
spacing: Dp,
onSliceFinished: () -> Unit,
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
modifier = modifier.height(38.dp),
) {
var currentIndex by remember {
mutableStateOf(0)
}
for (index in 0 until pageCount) {
Spacer(modifier = Modifier.width(20.dp))
val correctState = when {
index < currentIndex -> ProgressBarsState.COMPLETED
index == currentIndex -> ProgressBarsState.PLAYING
else -> ProgressBarsState.NOT_STARTED
}
HorizontalProgressBar(
modifier = Modifier.weight(1f),
progressBarsState = correctState,
index = currentIndex,
paused = paused
) {
onSliceFinished()
currentIndex++
}
}
}
}
Nothing happens when paused parameter changes coroutine seems to be continuing working and updating progress values , Is it connected somehow to threading or exactly what am i doing wrong here.
P.s i have tried to use Animatable value for animation and then call .stop() method on it when i want to pause animation but it has no effect whatsoever,
Upvotes: 1
Views: 969
Reputation: 199
you can pause the progress bar from the interactionSource of the pager state, instead of the isScrollInProgress
val isDragged = pagerState.interactionSource.collectIsDraggedAsState()
my code,
val pagerState =
rememberPagerState(initialPage = selectedStory, pageCount = { storyList.size })
HorizontalPager(
state = pagerState,
modifier = Modifier
.fillMaxSize()
.background(Color.Red),
) { page ->
val isShowed = page == pagerState.settledPage
val shouldPause = pagerState.interactionSource.collectIsDraggedAsState()
YourContent(isShowed, shouldPause) {
// on story finished
}
}
}
the ProgressBar:
private fun ProgressStoryIndicator(
shouldPause : Boolean,
isShowed: Boolean,
modifier: Modifier = Modifier,
onAnimationEnd: () -> Unit
) {
Row (
modifier = modifier
) {
var progress by remember {
mutableStateOf(0.00f)
}
val animatedProgress by animateFloatAsState(
targetValue = progress,
animationSpec = ProgressIndicatorDefaults.ProgressAnimationSpec, label = ""
)
if (isShowed) {
LaunchedEffect(key1 = shouldPause ) {
while (progress < 1f && isActive && shouldPause.not()) {
progress += 0.01f
delay(50)
}
//When the timer is not paused and animation completes then move to next page.
if (isActive && shouldPause.not()) {
delay(200)
onAnimationEnd()
}
}
}
LinearProgressIndicator(
progress = animatedProgress,
modifier = Modifier.fillMaxWidth(),
color = colorResource(id = R.color.color),
backgroundColor = Color.White,
strokeCap = StrokeCap.Round
)
}
}
Upvotes: 0
Reputation: 1305
You don't need to remember isScrollInProgress
state:
//var scrollInProgress by remember {
// mutableStateOf(pagerState.isScrollInProgress)
// }
SlicedProgressBar(
2,
modifier = Modifier
.fillMaxWidth()
.height(48.dp),
paused = pagerState.isScrollInProgress,
spacing = 10.dp
)
Upvotes: 0