Reputation: 2456
I have a LinearProgressIndicator
that correctly shows the current progress. Now I would like the progress to be animated and I thought this would be super simple with animateFloatAsState
. Well, not sure what I am not grokking, but with the code below, the progress is not animated, but immediately shown at the correct place.
@Composable
fun MyIndicator() {
val progressAnimDuration = 1500
val progressAnimation by animateFloatAsState(
targetValue = 0.35f
animationSpec = tween(durationMillis = progressAnimDuration, easing = FastOutSlowInEasing)
)
LinearProgressIndicator(
progress = progressAnimation,
...
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(20.dp)). // Rounded edges
)
}
So whenever I show that component on the screen, I would expect the progress to be animated to its correct progress state. But instead, the progress is not animated but immediately shown at the correct progress state.
What's wrong here? :)
Upvotes: 18
Views: 16662
Reputation: 528
I had a similar problem, in my case I used LaunchedEffect to update the progress from zero to the desired value
@Composable
fun AnimatedLinearProgressIndicator(
indicatorProgress: Float,
lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
) {
var progress by remember { mutableStateOf(0F) }
val progressAnimDuration = 1_500
val progressAnimation by animateFloatAsState(
targetValue = progress,
animationSpec = tween(durationMillis = progressAnimDuration, easing = FastOutSlowInEasing),
)
LinearProgressIndicator(
progress = { progressAnimation },
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(8.dp)),
)
LaunchedEffect(lifecycleOwner) {
progress = indicatorProgress
}
}
Upvotes: 30
Reputation: 31
@Composable
fun MyIndicator(indicatorProgress: Float) {
var progress by remember { mutableStateOf(0f) }
val progressAnimDuration = 1500
val progressAnimation by animateFloatAsState(
targetValue = progress,
animationSpec = tween(durationMillis = progressAnimDuration, easing = FastOutSlowInEasing)
)
Column(
modifier = Modifier
.background(Color.White)
.fillMaxSize(),
verticalArrangement = Arrangement.Center
) {
LinearProgressIndicator(
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(20.dp)),
progress = progressAnimation
)
}
LaunchedEffect(indicatorProgress) {
progress = indicatorProgress
}
}
A small modification made in the answer by @Dani Chucks.
Upvotes: 1
Reputation: 1
i solved it by having a mutable state at 0 then make it null at the end of the code to trigger recomposition
{
var starterProgressValue by remember { mutableStateOf<Float?>(0f) }
val actualProgress = 1f
AnimatedProgressBar(
progress = starterProgressValue ?: actualProgress,
duration = 3000,
modifier = Modifier
.align(Alignment.CenterStart)
.height(12.dp)
.fillMaxWidth()
)
starterProgressValue = null
}
Upvotes: 0
Reputation: 11
This is how I did it. I use progress indicator to simulate a loading effect, then jump to the login activity.
var currentProgress by remember { mutableFloatStateOf(0f) }
val context = LocalContext.current
// jump to Login Activity after animation
val currentPercentage by animateFloatAsState(
targetValue = currentProgress,
animationSpec = tween( durationMillis = 1000, easing = LinearEasing),
label = "progress",
finishedListener = { _ -> context.startActivity(Intent(context, LoginActivity3::class.java)) }
)
LaunchedEffect(key1 = Unit){
currentProgress = 1f
}
Box(modifier = Modifier.fillMaxSize(),contentAlignment = Alignment.Center)
{
Column(horizontalAlignment = Alignment.CenterHorizontally)
{
LinearProgressIndicator(
modifier = Modifier.width(220.dp).height(5.dp),
progress = currentPercentage,
color = colorResource(R.color.green_500)
)
}
}
Upvotes: 1
Reputation: 199
You case use the Animatable, but you need the LaunchEffect to trigger the animation
val percent = remember { Animatable(0f) }
LaunchedEffect(key1 = Unit, block = {
percent.animateTo(
targetValue = yourPercentage ,
animationSpec = tween(
durationMillis = (1000 * (1f - percent.value)).toInt(),
easing = FastOutLinearInEasing
)
)
})
LinearProgressIndicator(
progress = percent.value
)
Upvotes: 1
Reputation: 6938
In my case, it was worked -
var animationPlayed by remember {
mutableStateOf(false)
}
val currentPercentage = animateFloatAsState(targetValue =
if(animationPlayed) percentage else 0f,
animationSpec = tween( durationMillis = 4000)
)
LaunchedEffect(key1 = true){
animationPlayed=true
}
LinearProgressIndicator(...progress = currentPercentage)
Upvotes: 0
Reputation: 1
I found a very important parameter visibilityThreshold
in the animateFloatAsState
, you have to set it to 0.001f
to make it work.
Upvotes: 0