RangeSlider
Common
Component in Material 3 Compose
Range Sliders expand upon [Slider] using the same concepts but allow the user to select 2 values.
The two values are still bounded by the value range but they also cannot cross each other.
Use continuous Range Sliders to allow users to make meaningful selections that don’t require a specific values:
@sample androidx.compose.material3.samples.RangeSliderSample
Last updated:
Installation
dependencies {
implementation("androidx.compose.material3:material3:1.4.0-alpha02")
}
Overloads
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun RangeSlider(
value: ClosedFloatingPointRange<Float>,
onValueChange: (ClosedFloatingPointRange<Float>) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
valueRange: ClosedFloatingPointRange<Float> = 0f..1f,
@IntRange(from = 0) steps: Int = 0,
onValueChangeFinished: (() -> Unit)? = null,
colors: SliderColors = SliderDefaults.colors()
)
Parameters
name | description |
---|---|
value | current values of the RangeSlider. If either value is outside of [valueRange] provided, it will be coerced to this range. |
onValueChange | lambda in which values should be updated |
modifier | modifiers for the Range Slider layout |
enabled | whether or not component is enabled and can we interacted with or not |
valueRange | range of values that Range Slider values can take. Passed [value] will be coerced to this range |
steps | if positive, specifies the amount of discrete allowable values (in addition to the endpoints of the value range). Step values are evenly distributed across the range. If 0, the range slider will behave continuously and allow any value from the range. Must not be negative. |
onValueChangeFinished | lambda to be invoked when value change has ended. This callback shouldn't be used to update the range slider values (use [onValueChange] for that), but rather to know when the user has completed selecting a new value by ending a drag or a click. |
colors | [SliderColors] that will be used to determine the color of the Range Slider parts in different state. See [SliderDefaults.colors] to customize. |
@Composable
@ExperimentalMaterial3Api
fun RangeSlider(
value: ClosedFloatingPointRange<Float>,
onValueChange: (ClosedFloatingPointRange<Float>) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
valueRange: ClosedFloatingPointRange<Float> = 0f..1f,
onValueChangeFinished: (() -> Unit)? = null,
colors: SliderColors = SliderDefaults.colors(),
startInteractionSource: MutableInteractionSource = remember { MutableInteractionSource() },
endInteractionSource: MutableInteractionSource = remember { MutableInteractionSource() },
startThumb: @Composable (RangeSliderState) -> Unit = {
SliderDefaults.Thumb(
interactionSource = startInteractionSource,
colors = colors,
enabled = enabled
)
},
endThumb: @Composable (RangeSliderState) -> Unit = {
SliderDefaults.Thumb(
interactionSource = endInteractionSource,
colors = colors,
enabled = enabled
)
},
track: @Composable (RangeSliderState) -> Unit = { rangeSliderState ->
SliderDefaults.Track(
colors = colors,
enabled = enabled,
rangeSliderState = rangeSliderState
)
},
@IntRange(from = 0) steps: Int = 0
)
Parameters
name | description |
---|---|
value | current values of the RangeSlider. If either value is outside of [valueRange] provided, it will be coerced to this range. |
onValueChange | lambda in which values should be updated |
modifier | modifiers for the Range Slider layout |
enabled | whether or not component is enabled and can we interacted with or not |
onValueChangeFinished | lambda to be invoked when value change has ended. This callback shouldn't be used to update the range slider values (use [onValueChange] for that), but rather to know when the user has completed selecting a new value by ending a drag or a click. |
colors | [SliderColors] that will be used to determine the color of the Range Slider parts in different state. See [SliderDefaults.colors] to customize. |
startInteractionSource | the [MutableInteractionSource] representing the stream of [Interaction]s for the start thumb. You can create and pass in your own remember ed instance to observe. |
endInteractionSource | the [MutableInteractionSource] representing the stream of [Interaction]s for the end thumb. You can create and pass in your own remember ed instance to observe. |
steps | if positive, specifies the amount of discrete allowable values (in addition to the endpoints of the value range). Step values are evenly distributed across the range. If 0, the range slider will behave continuously and allow any value from the range. Must not be negative. |
startThumb | the start thumb to be displayed on the Range Slider. The lambda receives a [RangeSliderState] which is used to obtain the current active track. |
endThumb | the end thumb to be displayed on the Range Slider. The lambda receives a [RangeSliderState] which is used to obtain the current active track. |
track | the track to be displayed on the range slider, it is placed underneath the thumb. The lambda receives a [RangeSliderState] which is used to obtain the current active track. |
valueRange | range of values that Range Slider values can take. Passed [value] will be coerced to this range. |
@Composable
@ExperimentalMaterial3Api
fun RangeSlider(
state: RangeSliderState,
modifier: Modifier = Modifier,
enabled: Boolean = true,
colors: SliderColors = SliderDefaults.colors(),
startInteractionSource: MutableInteractionSource = remember { MutableInteractionSource() },
endInteractionSource: MutableInteractionSource = remember { MutableInteractionSource() },
startThumb: @Composable (RangeSliderState) -> Unit = {
SliderDefaults.Thumb(
interactionSource = startInteractionSource,
colors = colors,
enabled = enabled
)
},
endThumb: @Composable (RangeSliderState) -> Unit = {
SliderDefaults.Thumb(
interactionSource = endInteractionSource,
colors = colors,
enabled = enabled
)
},
track: @Composable (RangeSliderState) -> Unit = { rangeSliderState ->
SliderDefaults.Track(
colors = colors,
enabled = enabled,
rangeSliderState = rangeSliderState
)
}
)
Parameters
name | description |
---|---|
state | [RangeSliderState] which contains the current values of the RangeSlider. |
modifier | modifiers for the Range Slider layout |
enabled | whether or not component is enabled and can we interacted with or not |
colors | [SliderColors] that will be used to determine the color of the Range Slider parts in different state. See [SliderDefaults.colors] to customize. |
startInteractionSource | the [MutableInteractionSource] representing the stream of [Interaction]s for the start thumb. You can create and pass in your own remember ed instance to observe. |
endInteractionSource | the [MutableInteractionSource] representing the stream of [Interaction]s for the end thumb. You can create and pass in your own remember ed instance to observe. |
startThumb | the start thumb to be displayed on the Range Slider. The lambda receives a [RangeSliderState] which is used to obtain the current active track. |
endThumb | the end thumb to be displayed on the Range Slider. The lambda receives a [RangeSliderState] which is used to obtain the current active track. |
track | the track to be displayed on the range slider, it is placed underneath the thumb. The lambda receives a [RangeSliderState] which is used to obtain the current active track. |
Code Examples
RangeSliderSample
@OptIn(ExperimentalMaterial3Api::class)
@Preview
@Composable
fun RangeSliderSample() {
val rangeSliderState = remember {
RangeSliderState(
0f,
100f,
valueRange = 0f..100f,
onValueChangeFinished = {
// launch some business logic update with the state you hold
// viewModel.updateSelectedSliderValue(sliderPosition)
}
)
}
Column(modifier = Modifier.padding(horizontal = 16.dp)) {
val rangeStart = "%.2f".format(rangeSliderState.activeRangeStart)
val rangeEnd = "%.2f".format(rangeSliderState.activeRangeEnd)
Text(text = "$rangeStart .. $rangeEnd")
RangeSlider(
state = rangeSliderState,
modifier = Modifier.semantics { contentDescription = "Localized Description" }
)
}
}
StepRangeSliderSample
@OptIn(ExperimentalMaterial3Api::class)
@Preview
@Composable
fun StepRangeSliderSample() {
val rangeSliderState = remember {
RangeSliderState(
0f,
100f,
valueRange = 0f..100f,
onValueChangeFinished = {
// launch some business logic update with the state you hold
// viewModel.updateSelectedSliderValue(sliderPosition)
},
// Only allow multiples of 10. Excluding the endpoints of `valueRange`,
// there are 9 steps (10, 20, ..., 90).
steps = 9
)
}
Column(modifier = Modifier.padding(horizontal = 16.dp)) {
val rangeStart = rangeSliderState.activeRangeStart.roundToInt()
val rangeEnd = rangeSliderState.activeRangeEnd.roundToInt()
Text(text = "$rangeStart .. $rangeEnd")
RangeSlider(
state = rangeSliderState,
modifier = Modifier.semantics { contentDescription = "Localized Description" }
)
}
}
RangeSliderWithCustomComponents
@OptIn(ExperimentalMaterial3Api::class)
@Preview
@Composable
fun RangeSliderWithCustomComponents() {
val rangeSliderState = remember {
RangeSliderState(
0f,
100f,
valueRange = 0f..100f,
onValueChangeFinished = {
// launch some business logic update with the state you hold
// viewModel.updateSelectedSliderValue(sliderPosition)
}
)
}
val startInteractionSource = remember { MutableInteractionSource() }
val endInteractionSource = remember { MutableInteractionSource() }
val startThumbAndTrackColors =
SliderDefaults.colors(thumbColor = Color.Blue, activeTrackColor = Color.Red)
val endThumbColors = SliderDefaults.colors(thumbColor = Color.Green)
Column(modifier = Modifier.padding(horizontal = 16.dp)) {
RangeSlider(
state = rangeSliderState,
modifier = Modifier.semantics { contentDescription = "Localized Description" },
startInteractionSource = startInteractionSource,
endInteractionSource = endInteractionSource,
startThumb = {
Label(
label = {
PlainTooltip(modifier = Modifier.sizeIn(45.dp, 25.dp).wrapContentWidth()) {
Text("%.2f".format(rangeSliderState.activeRangeStart))
}
},
interactionSource = startInteractionSource
) {
SliderDefaults.Thumb(
interactionSource = startInteractionSource,
colors = startThumbAndTrackColors
)
}
},
endThumb = {
Label(
label = {
PlainTooltip(
modifier = Modifier.requiredSize(45.dp, 25.dp).wrapContentWidth()
) {
Text("%.2f".format(rangeSliderState.activeRangeEnd))
}
},
interactionSource = endInteractionSource
) {
SliderDefaults.Thumb(
interactionSource = endInteractionSource,
colors = endThumbColors
)
}
},
track = { rangeSliderState ->
SliderDefaults.Track(
colors = startThumbAndTrackColors,
rangeSliderState = rangeSliderState
)
}
)
}
}