Vertical Sliders allow users to make selections from a range of values.
VerticalCenteredSliderSample
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Preview
@Composable
fun VerticalCenteredSliderSample() {
val coroutineScope = rememberCoroutineScope()
val sliderState =
rememberSliderState(
// Only allow multiples of 10. Excluding the endpoints of `valueRange`,
// there are 9 steps (10, 20, ..., 90).
steps = 9,
valueRange = -50f..50f,
)
val snapAnimationSpec = MaterialTheme.motionScheme.fastEffectsSpec<Float>()
var currentValue by rememberSaveable { mutableFloatStateOf(sliderState.value) }
var animateJob: Job? by remember { mutableStateOf(null) }
sliderState.shouldAutoSnap = false
sliderState.onValueChange = { newValue ->
currentValue = newValue
// only update the sliderState instantly if dragging
if (sliderState.isDragging) {
animateJob?.cancel()
sliderState.value = newValue
}
}
sliderState.onValueChangeFinished = {
animateJob =
coroutineScope.launch {
animate(
initialValue = sliderState.value,
targetValue = currentValue,
animationSpec = snapAnimationSpec,
) { value, _ ->
sliderState.value = value
}
}
}
val interactionSource = remember { MutableInteractionSource() }
Column(modifier = Modifier.padding(horizontal = 16.dp)) {
Text(
modifier = Modifier.align(Alignment.CenterHorizontally),
text = "%.2f".format(sliderState.value),
)
Spacer(Modifier.height(16.dp))
VerticalSlider(
state = sliderState,
modifier =
Modifier.height(300.dp)
.align(Alignment.CenterHorizontally)
.progressSemantics(
currentValue,
sliderState.valueRange.start..sliderState.valueRange.endInclusive,
sliderState.steps,
),
interactionSource = interactionSource,
track = { SliderDefaults.CenteredTrack(sliderState = sliderState) },
reverseDirection = true,
)
}
}
VerticalSliderSample
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Preview
@Composable
fun VerticalSliderSample() {
val coroutineScope = rememberCoroutineScope()
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,
)
val snapAnimationSpec = MaterialTheme.motionScheme.fastEffectsSpec<Float>()
var currentValue by rememberSaveable { mutableFloatStateOf(sliderState.value) }
var animateJob: Job? by remember { mutableStateOf(null) }
sliderState.shouldAutoSnap = false
sliderState.onValueChange = { newValue ->
currentValue = newValue
// only update the sliderState instantly if dragging
if (sliderState.isDragging) {
animateJob?.cancel()
sliderState.value = newValue
}
}
sliderState.onValueChangeFinished = {
animateJob =
coroutineScope.launch {
animate(
initialValue = sliderState.value,
targetValue = currentValue,
animationSpec = snapAnimationSpec,
) { value, _ ->
sliderState.value = value
}
}
}
val interactionSource = remember { MutableInteractionSource() }
Column(modifier = Modifier.padding(horizontal = 16.dp)) {
Text(
modifier = Modifier.align(Alignment.CenterHorizontally),
text = "%.2f".format(sliderState.value),
)
Spacer(Modifier.height(16.dp))
VerticalSlider(
state = sliderState,
modifier =
Modifier.height(300.dp)
.align(Alignment.CenterHorizontally)
.progressSemantics(
currentValue,
sliderState.valueRange.start..sliderState.valueRange.endInclusive,
sliderState.steps,
),
interactionSource = interactionSource,
track = {
SliderDefaults.Track(
sliderState = sliderState,
modifier = Modifier.width(36.dp),
trackCornerSize = 12.dp,
)
},
reverseDirection = true,
)
}
}