In this article, we'll explore how to create a color picker using Jetpack Compose, leveraging Material 3 Slider components. A color is essentially a combination of different amounts of red, green, blue, and alpha values, and we'll manage these values using sliders in our color picker UI. A sample video is given below to get an idea about what we are going to do in this article.
Prerequisites:
Before diving into the tutorial, make sure you have a
- Basic Understanding of Jetpack Compose,
- The latest version of Android Studio installed and
- A Jetpack Compose project setup.
Step by Step Implementation
Step 1: Create a new project
To create a new project in the Android Studio, please refer to How to Create a new Project in Android Studio with Jetpack Compose.
Step 2: Creating the Color Picker Composable
We'll create a composable function named ColorPicker to encapsulate our color picker UI. This function will include sliders for adjusting the RGBA values and will display the current color in a box and the ARGB hex code in a Text composable.
@Composable
fun ColorPicker() {
// State variables for RGBA values
val alpha = rememberSaveable { mutableFloatStateOf(1f) }
val red = rememberSaveable { mutableFloatStateOf(0f) }
val green = rememberSaveable { mutableFloatStateOf(0f) }
val blue = rememberSaveable { mutableFloatStateOf(0f) }
// Derived state for the color based on RGBA values
val color by remember {
derivedStateOf {
Color(red.floatValue, green.floatValue, blue.floatValue, alpha.floatValue)
}
}
// UI layout using Scaffold and Column
Column(modifier = Modifier.padding(8.dp)) {
// Display the current color in a Box with a MaterialTheme shape
Row {
Box(
modifier = Modifier
.padding(10.dp, 0.dp)
.fillMaxWidth()
.height(80.dp)
.background(color, shape = MaterialTheme.shapes.large)
)
}
// Sliders for adjusting RGBA values
Column(
modifier = Modifier.padding(12.dp),
verticalArrangement = Arrangement.spacedBy(5.dp)
) {
ColorSlider("A", alpha, color.copy(1f))
ColorSlider("R", red, Color.Red)
ColorSlider("G", green, Color.Green)
ColorSlider("B", blue, Color.Blue)
}
// Add Hex code display
Box(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 12.dp, vertical = 8.dp),
contentAlignment = Alignment.Center
) {
Text(
text = color.toHexCode(),
style = MaterialTheme.typography.bodyLarge
)
}
}
}
Step 3: Creating the ColorSlider Composable
Next, we'll define a composable function named `ColorSlider` to create individual sliders for adjusting the RGBA values. This function will take a label, a mutable state for the slider value, and a color for the slider's active track.
/**
* A composable function that creates a slider for adjusting a float value associated with a color.
*
* @param label The label to display alongside the slider.
* @param valueState The mutable state holding the current value of the slider.
* @param color The color used for the active track of the slider.
*/
@Composable
fun ColorSlider(
label: String,
valueState: MutableState<Float>,
color: Color,
) {
/**
* Displays a slider for adjusting the given [valueState] associated with the provided [label].
* The slider's active track color is set to [color].
*/
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(6.dp)
) {
Text(text = label)
Slider(
value = valueState.value,
onValueChange = valueState.component2(),
colors = SliderDefaults.colors(
activeTrackColor = color
),
modifier = Modifier.weight(1f)
)
Text(
text = valueState.value.toColorInt().toString(),
modifier = Modifier.width(25.dp),
textAlign = TextAlign.End,
style = MaterialTheme.typography.bodySmall
)
}
}
Step 4: Adding Utility Functions
We'll also include an extension function `toColorInt()` to convert float values to integer color components.
/**
* Converts a float value in the range [0, 1] to an integer color component in the range [0, 255].
*
* @return The integer representation of the color component.
*/
fun Float.toColorInt(): Int = (this * 255 + 0.5f).toInt()
// Convert Color to Hex Code
fun Color.toHexCode(): String {
val a = (alpha * 255).toInt()
val r = (red * 255).toInt()
val g = (green * 255).toInt()
val b = (blue * 255).toInt()
return String.format("#%02X%02X%02X%02X", a, r, g, b)
}
Step 5: Entire code for MainActivity.kt
Here's the entire code for MainActivity.kt. We can use the ColorPicker Composable in the MainActivity or other composables.
MainActivity.kt:
package com.geeksforgeeks.demo
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.*
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.*
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MaterialTheme {
ColorPicker()
}
}
}
}
@Composable
fun ColorPicker() {
// State variables for RGBA values
val alpha = rememberSaveable { mutableFloatStateOf(1f) }
val red = rememberSaveable { mutableFloatStateOf(0f) }
val green = rememberSaveable { mutableFloatStateOf(0f) }
val blue = rememberSaveable { mutableFloatStateOf(0f) }
// Derived state for the color based on RGBA values
val color by remember {
derivedStateOf {
Color(red.floatValue, green.floatValue, blue.floatValue, alpha.floatValue)
}
}
// UI layout using Scaffold and Column
Column(modifier = Modifier.padding(8.dp)) {
// Display the current color in a Box with a MaterialTheme shape
Row {
Box(
modifier = Modifier
.padding(10.dp, 0.dp)
.fillMaxWidth()
.height(80.dp)
.background(color, shape = MaterialTheme.shapes.large)
)
}
// Sliders for adjusting RGBA values
Column(
modifier = Modifier.padding(12.dp),
verticalArrangement = Arrangement.spacedBy(5.dp)
) {
ColorSlider("A", alpha, color.copy(1f))
ColorSlider("R", red, Color.Red)
ColorSlider("G", green, Color.Green)
ColorSlider("B", blue, Color.Blue)
}
// Add Hex code display
Box(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 12.dp, vertical = 8.dp),
contentAlignment = Alignment.Center
) {
Text(
text = color.toHexCode(),
style = MaterialTheme.typography.bodyLarge
)
}
}
}
/**
* A composable function that creates a slider for adjusting a float value associated with a color.
*
* @param label The label to display alongside the slider.
* @param valueState The mutable state holding the current value of the slider.
* @param color The color used for the active track of the slider.
*/
@Composable
fun ColorSlider(
label: String,
valueState: MutableState<Float>,
color: Color,
) {
/**
* Displays a slider for adjusting the given [valueState] associated with the provided [label].
* The slider's active track color is set to [color].
*/
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(6.dp)
) {
Text(text = label)
Slider(
value = valueState.value,
onValueChange = valueState.component2(),
colors = SliderDefaults.colors(
activeTrackColor = color
),
modifier = Modifier.weight(1f)
)
Text(
text = valueState.value.toColorInt().toString(),
modifier = Modifier.width(25.dp),
textAlign = TextAlign.End,
style = MaterialTheme.typography.bodySmall
)
}
}
/**
* Converts a float value in the range [0, 1] to an integer color component in the range [0, 255].
*
* @return The integer representation of the color component.
*/
fun Float.toColorInt(): Int = (this * 255 + 0.5f).toInt()
fun Color.toHexCode(): String {
val a = (alpha * 255).toInt()
val r = (red * 255).toInt()
val g = (green * 255).toInt()
val b = (blue * 255).toInt()
return String.format("#%02X%02X%02X%02X", a, r, g, b)
}
Output:
Conclusion
In this tutorial, we've learned how to create a color picker using Jetpack Compose and Material 3 Slider components. By adjusting the RGBA values with sliders, users can easily select their desired colors.