I am building an Android App which needs to create several vertical sliders in the same page for music equalizer adjustment, but I can only find horizontal sliders from the official material design documents.
I try to implement default slider from official documents and rotate it with modifier and it works, but the problem is that I am not able to adjust the height now using Modifier
.
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Row(modifier =
Modifier
.fillMaxWidth()
.fillMaxHeight(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
slider()
slider()
slider()
slider()
slider()
slider()
slider()
}
}
}
}
@Composable
fun slider() : Int
{
var sliderPosition by remember { mutableStateOf(0f) }
Slider(
modifier = Modifier
.width(50.dp)
.height(120.dp)
.background(color = Color.Red)
.wrapContentSize()
.rotate(270F)
.padding(start = 0.5.dp),
value = sliderPosition,
valueRange = 1f..10f,
onValueChange = {sliderPosition = it}
)
return sliderPosition.roundToInt()
}
Your rotated slider doesn't fill available height, because it gets a wrong constraint after rotation. To fix this you first of all need to swap width
and height
values.
Next, Modifier.rotate
won't change the view position, so you need to manually update it after rotation. To understand what's going on, you can run the following code:
Box(
contentAlignment = Alignment.Center,
modifier = Modifier.fillMaxSize()
) {
Box(Modifier
.size(100.dp, 50.dp)
.border(width = 1.dp, color = Color.Red)
.rotate(90f)
.background(Color.Green))
}
It'll produce the following view:
As you can see, real view frame is shown with the red border, and your view has an unexpected offset.
To fix it, you can use Modifier.layout
: you need to swap constraints and result view size dimensions, and revert the offset.
Also I'm using Modifier.graphicsLayer
with transformOrigin
set to zero point, so it's easier to calculate an offset needed in Modifier.layout
.
And the last part, size modifier should be placed after Modifier.layout
, in order to get parent view constraints instead of this static ones during layout
. And layout
should be placed after rotation. Check out more about why modifiers order matters in this answer
Final modifier for your slider:
Modifier
.graphicsLayer {
rotationZ = 270f
transformOrigin = TransformOrigin(0f, 0f)
}
.layout { measurable, constraints ->
val placeable = measurable.measure(
Constraints(
minWidth = constraints.minHeight,
maxWidth = constraints.maxHeight,
minHeight = constraints.minWidth,
maxHeight = constraints.maxHeight,
)
)
layout(placeable.height, placeable.width) {
placeable.place(-placeable.width, 0)
}
}
.width(120.dp)
.height(50.dp)