Skip to content

Instantly share code, notes, and snippets.

@Kyriakos-Georgiopoulos
Last active July 4, 2025 08:08
Show Gist options
  • Save Kyriakos-Georgiopoulos/eba7d082ba190b5eb082e331f2a0875b to your computer and use it in GitHub Desktop.
Save Kyriakos-Georgiopoulos/eba7d082ba190b5eb082e331f2a0875b to your computer and use it in GitHub Desktop.
Countdown Animation
data class GameCountdownState(
val durationMills: Int = 3000,
val circleColor: Color = Color.Yellow,
val textColor: Color = Color.Yellow
)
Composable
fun CountdownScreen(
state: GameCountdownState,
onFinish: () -> Unit,
) {
AnimateCircle(
durationMills = state.durationMills,
circleColor = state.circleColor,
)
Box(
contentAlignment = Alignment.Center,
) {
CountdownText(
durationMills = state.durationMills,
color = state.textColor,
onFinish = onFinish,
)
}
}
@Composable
fun AnimateCircle(
durationMills: Int,
circleColor: Color,
) {
var startTransition by remember {
mutableStateOf(false)
}
LaunchedEffect(Unit) {
startTransition = true
}
val progress: Float by animateFloatAsState(
targetValue = if (startTransition) 1f else 0f,
animationSpec = tween(
durationMillis = durationMills,
easing = LinearEasing,
),
label = "circleProgress",
)
Canvas(
modifier = Modifier.fillMaxSize(),
) {
val radius = 100.dp.toPx()
val center = Offset(
x = (size.width / 2) - radius,
y = size.height / 2 - radius,
)
drawArc(
color = circleColor,
startAngle = -90f,
sweepAngle = 360 * progress,
useCenter = false,
size = Size(
width = radius * 2,
height = radius * 2,
),
topLeft = center,
style = Stroke(width = 8.dp.toPx()),
)
drawCircle(
color = Color.White,
alpha = 0.25f,
center = Offset(
x = size.width / 2,
y = size.height / 2,
),
radius = radius,
style = Stroke(width = 8.dp.toPx()),
)
}
}
@Composable
fun CountdownText(
durationMills: Int,
color: Color,
onFinish: (() -> Unit)? = null,
) {
var timeLeftInMillis by remember(durationMills) {
mutableIntStateOf(durationMills)
}
LaunchedEffect(durationMills) {
launch {
while (timeLeftInMillis > 0) {
delay(1000)
timeLeftInMillis -= 1000
}
onFinish?.invoke()
}
}
val seconds = (timeLeftInMillis / 1000 % 60)
Text(
modifier = Modifier
.padding(16.dp),
text = seconds.toString(),
textAlign = TextAlign.Center,
style = TextStyle(color = color, fontSize = 72.sp),
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment