Sliders allow users to make selections from a range of values.
CenteredSliderSample
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Preview
@Composable
fun CenteredSliderSample() {
val sliderState =
rememberSliderState(
valueRange = -50f..50f,
onValueChangeFinished = {
// launch some business logic update with the state you hold
// viewModel.updateSelectedSliderValue(sliderPosition)
},
)
val interactionSource = remember { MutableInteractionSource() }
Column(modifier = Modifier.padding(horizontal = 16.dp)) {
Text(text = "%.2f".format(sliderState.value))
Slider(
state = sliderState,
interactionSource = interactionSource,
thumb = { SliderDefaults.Thumb(interactionSource = interactionSource) },
track = { SliderDefaults.CenteredTrack(sliderState = sliderState) },
)
}
}
SliderSample
@Preview
@Composable
fun SliderSample() {
var sliderPosition by rememberSaveable { mutableStateOf(0f) }
Column(modifier = Modifier.padding(horizontal = 16.dp)) {
Text(text = "%.2f".format(sliderPosition))
Slider(value = sliderPosition, onValueChange = { sliderPosition = it })
}
}
SliderWithCustomThumbSample
@OptIn(ExperimentalMaterial3Api::class)
@Preview
@Composable
fun SliderWithCustomThumbSample() {
var sliderPosition by rememberSaveable { mutableStateOf(0f) }
val interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
Column(modifier = Modifier.padding(horizontal = 16.dp)) {
Slider(
value = sliderPosition,
onValueChange = { sliderPosition = it },
valueRange = 0f..100f,
interactionSource = interactionSource,
onValueChangeFinished = {
// launch some business logic update with the state you hold
// viewModel.updateSelectedSliderValue(sliderPosition)
},
thumb = {
Label(
label = {
PlainTooltip(modifier = Modifier.sizeIn(45.dp, 25.dp).wrapContentWidth()) {
Text("%.2f".format(sliderPosition))
}
},
interactionSource = interactionSource,
) {
Icon(
imageVector = Icons.Filled.Favorite,
contentDescription = null,
modifier = Modifier.size(ButtonDefaults.IconSize),
tint = Color.Red,
)
}
},
)
}
}
SliderWithCustomTrackAndThumbSample
@Preview
@Composable
fun SliderWithCustomTrackAndThumbSample() {
val sliderState =
rememberSliderState(
valueRange = 0f..100f,
onValueChangeFinished = {
// launch some business logic update with the state you hold
// viewModel.updateSelectedSliderValue(sliderPosition)
},
)
val interactionSource = remember { MutableInteractionSource() }
val colors = SliderDefaults.colors(thumbColor = Color.Red, activeTrackColor = Color.Red)
Column(modifier = Modifier.padding(horizontal = 16.dp)) {
Text(text = "%.2f".format(sliderState.value))
Slider(
state = sliderState,
interactionSource = interactionSource,
thumb = {
SliderDefaults.Thumb(interactionSource = interactionSource, colors = colors)
},
track = { SliderDefaults.Track(colors = colors, sliderState = sliderState) },
)
}
}
SliderWithTrackIconsSample
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Preview
@Composable
fun SliderWithTrackIconsSample() {
val sliderState =
rememberSliderState(
valueRange = 0f..100f,
onValueChangeFinished = {
// launch some business logic update with the state you hold
// viewModel.updateSelectedSliderValue(sliderPosition)
},
)
val interactionSource = remember { MutableInteractionSource() }
val startIcon = rememberVectorPainter(Icons.Filled.MusicNote)
val endIcon = rememberVectorPainter(Icons.Filled.MusicOff)
Column(modifier = Modifier.padding(horizontal = 16.dp)) {
Text(text = "%.2f".format(sliderState.value))
Slider(
state = sliderState,
interactionSource = interactionSource,
track = {
val iconSize = DpSize(20.dp, 20.dp)
val iconPadding = 10.dp
val thumbTrackGapSize = 6.dp
val activeIconColor = SliderDefaults.colors().activeTickColor
val inactiveIconColor = SliderDefaults.colors().inactiveTickColor
val trackIconStart: DrawScope.(Offset, Color) -> Unit = { offset, color ->
translate(offset.x + iconPadding.toPx(), offset.y) {
with(startIcon) {
draw(iconSize.toSize(), colorFilter = ColorFilter.tint(color))
}
}
}
val trackIconEnd: DrawScope.(Offset, Color) -> Unit = { offset, color ->
translate(offset.x - iconPadding.toPx() - iconSize.toSize().width, offset.y) {
with(endIcon) {
draw(iconSize.toSize(), colorFilter = ColorFilter.tint(color))
}
}
}
SliderDefaults.Track(
sliderState = sliderState,
modifier =
Modifier.height(36.dp).drawWithContent {
drawContent()
val yOffset = size.height / 2 - iconSize.toSize().height / 2
val activeTrackStart = 0f
val activeTrackEnd =
size.width * sliderState.coercedValueAsFraction -
thumbTrackGapSize.toPx()
val inactiveTrackStart = activeTrackEnd + thumbTrackGapSize.toPx() * 2
val inactiveTrackEnd = size.width
val activeTrackWidth = activeTrackEnd - activeTrackStart
val inactiveTrackWidth = inactiveTrackEnd - inactiveTrackStart
if (
iconSize.toSize().width < activeTrackWidth - iconPadding.toPx() * 2
) {
trackIconStart(Offset(activeTrackStart, yOffset), activeIconColor)
trackIconEnd(Offset(activeTrackEnd, yOffset), activeIconColor)
}
if (
iconSize.toSize().width <
inactiveTrackWidth - iconPadding.toPx() * 2
) {
trackIconStart(
Offset(inactiveTrackStart, yOffset),
inactiveIconColor,
)
trackIconEnd(Offset(inactiveTrackEnd, yOffset), inactiveIconColor)
}
},
trackCornerSize = 12.dp,
drawStopIndicator = null,
thumbTrackGapSize = thumbTrackGapSize,
)
},
)
}
}
StepsSliderSample
@Preview
@Composable
fun StepsSliderSample() {
val sliderState =
rememberSliderState(
// Only allow multiples of 10. Excluding the endpoints of `valueRange`,
// there are 9 steps (10, 20, ..., 90).
steps = 9,
valueRange = 0f..100f,
onValueChangeFinished = {
// launch some business logic update with the state you hold
// viewModel.updateSelectedSliderValue(sliderPosition)
},
)
Column(modifier = Modifier.padding(horizontal = 16.dp)) {
Text(text = "%.2f".format(sliderState.value))
Slider(state = sliderState)
}
}