What You Will Build

A full-screen music player with a gradient background, album art placeholder, song title and artist, a seekbar slider, and playback controls (previous, play/pause, next). The play/pause button toggles state with a filled icon button.

Why This Pattern Matters

Music player UIs teach vertical gradient backgrounds, Slider customization, icon state toggling, and centered column layouts — patterns used in podcast apps, audiobook players, and media controls.

Step 1: Gradient Background

Column(
    modifier = Modifier
        .fillMaxSize()
        .background(
            Brush.verticalGradient(
                listOf(Color(0xFF1A1A2E), Color(0xFF16213E))
            )
        )
        .padding(24.dp),
    horizontalAlignment = Alignment.CenterHorizontally
) {
    // Content here
}

Step 2: Album Art Card

Card(
    Modifier.size(280.dp),
    shape = RoundedCornerShape(20.dp)
) {
    Box(
        Modifier.fillMaxSize()
            .background(
                Brush.linearGradient(
                    listOf(Color(0xFF6C63FF), Color(0xFFFF6584))
                )
            ),
        contentAlignment = Alignment.Center
    ) {
        Icon(Icons.Default.MusicNote, null,
             modifier = Modifier.size(80.dp), tint = Color.White)
    }
}

Step 3: Seekbar and Controls

var isPlaying by remember { mutableStateOf(false) }
var progress by remember { mutableFloatStateOf(0.3f) }

// Song info
Text("Summer Vibes", color = Color.White,
     fontSize = 24.sp, fontWeight = FontWeight.Bold)
Text("Artist Name", color = Color.White.copy(alpha = 0.7f))

// Seekbar
Slider(
    value = progress,
    onValueChange = { progress = it },
    colors = SliderDefaults.colors(
        thumbColor = Color.White,
        activeTrackColor = Color(0xFF6C63FF)
    )
)
Row(Modifier.fillMaxWidth(),
    horizontalArrangement = Arrangement.SpaceBetween) {
    Text("1:15", color = Color.White.copy(alpha = 0.5f))
    Text("3:45", color = Color.White.copy(alpha = 0.5f))
}

// Playback controls
Row(
    horizontalArrangement = Arrangement.spacedBy(24.dp),
    verticalAlignment = Alignment.CenterVertically
) {
    IconButton(onClick = {}) {
        Icon(Icons.Default.SkipPrevious, "Previous",
             tint = Color.White, modifier = Modifier.size(36.dp))
    }
    FilledIconButton(
        onClick = { isPlaying = !isPlaying },
        modifier = Modifier.size(64.dp)
    ) {
        Icon(
            if (isPlaying) Icons.Default.Pause
            else Icons.Default.PlayArrow,
            "Play/Pause", modifier = Modifier.size(36.dp)
        )
    }
    IconButton(onClick = {}) {
        Icon(Icons.Default.SkipNext, "Next",
             tint = Color.White, modifier = Modifier.size(36.dp))
    }
}

Tips and Pitfalls

  • Brush.verticalGradient creates the dark atmospheric background. Two similar dark colors create depth without distraction.
  • SliderDefaults.colors lets you customize thumb and track colors to match your theme.
  • FilledIconButton for play/pause makes it stand out as the primary action. Standard IconButton for secondary actions (skip).
  • Real app extension: Connect to ExoPlayer and update the slider with LaunchedEffect polling current position.

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.