What You Will Build
Neon-styled UI elements that pulse with a glow effect: a neon text heading, a glowing circle with multiple glow rings, and a card with an animated neon border. All elements pulse between dim and bright using an infinite transition. The result is a cyberpunk / synthwave aesthetic.
Why This Pattern Matters
Neon glow effects are popular in gaming apps, music players, and dark-themed dashboards. This pattern teaches you drawBehind for custom drawing behind composables, multiple concentric glow rings via loop-based drawing, and animated alpha for the pulsing effect.
Step 1: Infinite Pulsing Animations
@Composable
fun NeonGlowScreen() {
val infiniteTransition = rememberInfiniteTransition(
label = "neon"
)
// Pulsing alpha for glow intensity
val glowAlpha by infiniteTransition.animateFloat(
initialValue = 0.3f,
targetValue = 1f,
animationSpec = infiniteRepeatable(
animation = tween(1500),
repeatMode = RepeatMode.Reverse
),
label = "glow"
)
// Hue shift for color cycling (optional)
val hueShift by infiniteTransition.animateFloat(
initialValue = 0f,
targetValue = 360f,
animationSpec = infiniteRepeatable(
animation = tween(5000, easing = LinearEasing)
),
label = "hue"
)
Step 2: Neon Text with drawBehind Glow
Text(
"Neon Glow",
fontSize = 36.sp,
fontWeight = FontWeight.Bold,
color = Color(0xFF00FF88).copy(alpha = glowAlpha),
modifier = Modifier.drawBehind {
drawRect(
color = Color(0xFF00FF88)
.copy(alpha = glowAlpha * 0.3f),
style = Stroke(width = 4f)
)
}
)
Step 3: Glowing Circle with Multiple Rings
Box(
modifier = Modifier
.size(150.dp)
.drawBehind {
// Draw 3 concentric glow rings
for (i in 1..3) {
drawCircle(
color = Color(0xFF00BFFF)
.copy(alpha = glowAlpha * (0.3f / i)),
radius = size.minDimension / 2 +
i * 20f
)
}
// Inner bright circle
drawCircle(
color = Color(0xFF00BFFF)
.copy(alpha = glowAlpha)
)
}
)
Step 4: Neon Border Card
Card(
modifier = Modifier.padding(horizontal = 40.dp),
shape = RoundedCornerShape(16.dp),
colors = CardDefaults.cardColors(
containerColor = Color(0xFF1A1A2E)
),
border = BorderStroke(
2.dp,
Color(0xFFFF00FF).copy(alpha = glowAlpha)
)
) {
Column(
Modifier.padding(24.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text("Neon Card",
color = Color(0xFFFF00FF)
.copy(alpha = glowAlpha),
fontWeight = FontWeight.Bold,
fontSize = 20.sp)
Text("Glowing effect",
color = Color.White.copy(alpha = 0.7f))
}
}
Tips and Pitfalls
- Dark background is essential: Neon effects only work against dark backgrounds. Use
Color(0xFF0A0A0A)or similar. - Glow ring math: Each ring has
alpha = glowAlpha * (0.3f / i)where i increases. This creates a natural falloff from bright core to dim outer glow. - Performance:
drawBehindis efficient because it draws directly on the Canvas without triggering recomposition. The animation only changes the alpha value. - True glow with blur: For a soft, realistic neon glow on API 31+, apply
BlurEffectviagraphicsLayer { renderEffect = ... }on a colored layer behind the text.
Min SDK: API 21+ with Compose 1.0+