What You Will Build
A set of colored cards that slide in from the right with staggered timing — each card waits 200ms before the next one starts. The cards use spring physics with low damping for a bouncy entrance. This pattern is used in onboarding flows, list reveals, and dashboard loading states.
Why This Pattern Matters
Staggered animations add polish and visual hierarchy to list content. This project teaches the Animatable API, coroutine-based sequencing with delay, and how to combine alpha and translation for slide-in-fade-in effects.
Step 1: Create Animatable Values for Each Item
@Composable
fun SequencedAnimationScreen() {
val items = listOf(
Color(0xFFFF6B6B), Color(0xFF4ECDC4),
Color(0xFF45B7D1), Color(0xFFFFA07A),
Color(0xFF98D8C8)
)
val visibilities = remember {
items.map { Animatable(0f) }
}
var started by remember { mutableStateOf(false) }
// ...
}
Step 2: Launch Staggered Animations
A LaunchedEffect watches the started flag. When triggered, it resets all values to 0 and then launches each animation with an increasing delay:
LaunchedEffect(started) {
if (started) {
// Reset all
visibilities.forEach { it.snapTo(0f) }
// Stagger launch
visibilities.forEachIndexed { i, anim ->
delay(200L * i)
launch {
anim.animateTo(1f, spring(dampingRatio = 0.5f))
}
}
}
}
Step 3: Apply Alpha and Translation
items.forEachIndexed { i, color ->
Box(
Modifier
.fillMaxWidth().height(60.dp)
.graphicsLayer(
alpha = visibilities[i].value,
translationX = (1f - visibilities[i].value) * 300f
)
.clip(RoundedCornerShape(12.dp))
.background(color)
.padding(16.dp)
) {
Text("Step ${i + 1}", color = Color.White)
}
Spacer(Modifier.height(12.dp))
}
Tips and Pitfalls
- Animatable vs animateFloatAsState:
Animatablegives yousnapTo(instant reset) and imperative control.animateFloatAsStateis simpler but harder to sequence. - launch {} inside forEachIndexed: Each animation runs concurrently after its delay. Without
launch, they would run sequentially (each waiting for the previous to finish). - dampingRatio = 0.5f gives visible overshoot. Use 0.8f for subtle bounce or 1.0f for no bounce.
- Reverse animation: To dismiss, reverse the loop order and animate to 0f.