What You Will Build

A branded splash screen with a deep gradient background, a pulsing and rotating radial glow ring behind the logo, and fading text. The animation uses three independent infinite transitions for scale, alpha, and rotation. This is the app launch experience pattern used by premium apps.

Why This Pattern Matters

Splash screens set the tone for an app. While the Android 12+ SplashScreen API handles the initial launch, custom animated splash screens are still used for loading states, onboarding entry points, and branded transitions between major app sections.

Step 1: Three Infinite Transitions

val infiniteTransition = rememberInfiniteTransition(label = "splash")

val scale by infiniteTransition.animateFloat(
    0.8f, 1.2f,
    infiniteRepeatable(tween(2000), RepeatMode.Reverse),
    label = "sc"
)
val alpha by infiniteTransition.animateFloat(
    0.5f, 1f,
    infiniteRepeatable(tween(1500), RepeatMode.Reverse),
    label = "al"
)
val rotation by infiniteTransition.animateFloat(
    0f, 360f,
    infiniteRepeatable(tween(8000, easing = LinearEasing)),
    label = "rot"
)

Step 2: Gradient Background and Glow Ring

Box(
    Modifier.fillMaxSize().background(
        Brush.verticalGradient(listOf(
            Color(0xFF1A1A2E),
            Color(0xFF16213E),
            Color(0xFF0F3460)
        ))
    ),
    contentAlignment = Alignment.Center
) {
    // Rotating, pulsing glow ring
    Box(
        Modifier.size(180.dp)
            .scale(scale)
            .graphicsLayer(rotationZ = rotation)
            .clip(CircleShape)
            .background(
                Brush.radialGradient(listOf(
                    Color(0xFF4ECDC4).copy(alpha = 0.3f),
                    Color.Transparent
                ))
            )
    )

    // Logo text
    Column(horizontalAlignment = Alignment.CenterHorizontally) {
        Text("BD", fontSize = 64.sp,
            fontWeight = FontWeight.Bold,
            color = Color.White.copy(alpha = alpha))
        Spacer(Modifier.height(8.dp))
        Text("Beautiful Design",
            color = Color.White.copy(alpha = alpha * 0.7f),
            style = MaterialTheme.typography.bodyLarge)
    }
}

Tips and Pitfalls

  • graphicsLayer(rotationZ = ...) applies rotation without triggering re-layout. It operates at the drawing layer, which is more efficient than rotationEffect.
  • Different tween durations (2000, 1500, 8000) desynchronize the animations so the effect never looks repetitive.
  • Brush.radialGradient fading to Transparent creates the soft glow edge. A solid circle would look harsh.
  • For production: Add a LaunchedEffect with delay() to navigate away after 2-3 seconds, or tie it to a loading state with collectAsState().

Min SDK: 21 | Compose BOM: 2024.01.00+

Get New Tutorials by Email

No spam. Just clear, practical breakdowns you can apply right away.

Enjoy this tutorial?

Get new practical tech tutorials in your inbox.