I am making a desktop compose application.
I had a LazyColumn
with Divider
separating items. LazyColumn
's width may not fit in window so I made the LazyColumn
horizontally scrollable by enclosing it inside a Box
with horizontalScroll()
modifier set.
Now LazyColumn
became horizontal scrollable as well. But strangely the Divider
's separating the items disappeared.
After digging into it for a while, I figured out that Divider
's became invisible only when placed inside a horizontally scrollable parent.
Here is a minimal reproduction of observed behavior where red Divider
is clearly invisible when horizontalScroll(rememberScrollState())
modifier is set in enclosing Box
.
fun main() = application {
Window(onCloseRequest = ::exitApplication) {
Box(
Modifier.fillMaxSize()
.background(Color.Green)
.horizontalScroll(rememberScrollState())
) {
Divider(thickness = 10.dp, color = Color.Red)
}
}
}
As it can be seen that the red Divider
is invisible for above code.
Expected Output:
With verticalScroll()
or no scroll modifier at all works fine as expected.
fun main() = application {
Window(onCloseRequest = ::exitApplication) {
Box(
Modifier.fillMaxSize()
.background(Color.Green)
.verticalScroll(rememberScrollState())
) {
Divider(thickness = 10.dp, color = Color.Red)
}
}
}
Correct output as expected, the red Divider
is clearly visible for above code.
Version info
kotlin("jvm") version "1.5.21"
id("org.jetbrains.compose") version "1.0.0-alpha3"
I'd like to know if this is a bug? or is there a way to fix this.
No, this is not a bug.
Divider
is used to take the full width, just like any other view with the fillMaxWidth()
modifier.
But inside horizontalScroll
this modifier is ignored because it is ambiguous: horizontalScroll
wraps the size of the content, so the maxWidth
constraint in this area is infinite.
From fillMaxWidth
documentation:
If the incoming maximum width is
Constraints.Infinity
this modifier will have no effect.
I haven't found any documentation mentioning horizontalScroll
effects Constraints
, you can see maintainer's answer on the same issue, or you can test it by yourself like this:
Box {
BoxWithConstraints(Modifier.fillMaxSize()) {
// output 1080 2082
println("non scrollable max dimensions: ${constraints.maxWidth} ${constraints.maxHeight}")
}
BoxWithConstraints(Modifier.fillMaxSize().horizontalScroll(rememberScrollState())) {
// output 2147483647 2082
println("scrollable max dimensions: ${constraints.maxWidth} ${constraints.maxHeight}")
}
}
In this case you need to specify the width explicitly, e.g:
Box(
Modifier
.fillMaxSize()
.background(Color.Green)
.horizontalScroll(rememberScrollState())
) {
var width by remember { mutableStateOf(0) }
val density = LocalDensity.current
val widthDp = remember(width, density) { with(density) { width.toDp() } }
LazyColumn(
modifier = Modifier.onSizeChanged {
width = it.width
}
) {
items(100) {
Text("$it".repeat(it))
Divider(
thickness = 10.dp,
color = Color.Red,
modifier = Modifier.width(widthDp)
)
}
}
}
Note that when the top part of your LazyColumn
is smaller than the bottom one, as in my example, the width will be smaller at first (to accommodate only the visible part), but after scrolling down and back up, the width will not be restored to its original width because the Divider
width modifier will not let it shrink back down. If you need to prevent this, you need to calculate the `width' based only on the visible elements, which is more complicated.