Is it possible to make an animation like gif with Jetpack Compose?

One of the ways to do is using Animatables that animate scale and alpha after each other.

create a class that contains 2 Animatables
class AnimatedCountdownTimer(
private val coroutineScope: CoroutineScope
) {
private val animatableScale = Animatable(1f)
private val animatableAlpha = Animatable(1f)
val scale: Float
get() = animatableScale.value
val alpha: Float
get() = animatableAlpha.value
fun start(initialValue: Int, endValue: Int, onChange: (Int) -> Unit) {
var value = initialValue
coroutineScope.launch {
while (value > endValue - 1) {
onChange(value)
animatableScale.snapTo(1f)
animatableAlpha.snapTo(1f)
animatableScale.animateTo(2f, animationSpec = tween(750))
animatableAlpha.animateTo(0f, animationSpec = tween(250))
value--
}
}
}
}
And use it as
@Preview
@Composable
fun TimerTest() {
var timer by remember {
mutableStateOf(5)
}
val coroutineScope = rememberCoroutineScope()
val animatedCountdownTimer = remember {
AnimatedCountdownTimer(coroutineScope)
}
Column(
modifier = Modifier.fillMaxSize().padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
modifier = Modifier.graphicsLayer {
scaleX = animatedCountdownTimer.scale
scaleY = animatedCountdownTimer.scale
alpha = animatedCountdownTimer.alpha
},
text = "$timer",
fontSize = 120.sp,
fontWeight = FontWeight.Bold,
color = Color.Gray
)
Spacer(Modifier.height(20.dp))
Button(
modifier = Modifier.fillMaxWidth(),
onClick = {
animatedCountdownTimer.start(5, 0) {
timer = it
}
}
) {
Text("Start")
}
}
}
If you don't want to scale to 1f after animation end just ad if block so it can stay at scale. Any param can be customized easily time durations or max scale.
If you wish to keep last number scaled you can use it like this
coroutineScope.launch {
while (value > endValue - 1) {
onChange(value)
animatableScale.snapTo(1f)
animatableAlpha.snapTo(1f)
animatableScale.animateTo(2f, animationSpec = tween(750))
if (value > endValue) {
animatableAlpha.animateTo(0f, animationSpec = tween(250))
}
value--
}
}
Absolutely! You will need LaunchedEffect and mutableStateOf composables to manage the state of the timer and update.

@Composable
fun CountdownTimer() {
val totalTime = 5 // Total time in seconds
var restart by remember { mutableStateOf(0) }
var timeLeft by remember {
mutableStateOf(totalTime)
}
val anim = remember { Animatable(0f) }
LaunchedEffect(restart) {
while (timeLeft > 0) {
delay(1000)
timeLeft--
anim.snapTo(0f)
anim.animateTo(1f)
}
}
Column (
horizontalAlignment=Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
){
Text(
modifier = Modifier
.alpha(anim.value)
.scale(anim.value/2f+.5f)
,
text = "${timeLeft}",
fontSize = 64.sp,
color = Color.DarkGray
)
Button(onClick = {
timeLeft = totalTime
restart++
}) {
Text(text = "Reset")
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With