当放置在具有 horizo​​ntalScroll 修饰符集的可组合项内时,分隔符可组合项变得不可见。这是一个错误吗?

Divider composable becomes invisible when placed inside composable with horizontalScroll modifier set. Is this a bug?

背景

我正在制作桌面撰写应用程序。

我有一个 LazyColumnDivider 分隔项。 LazyColumn 的宽度可能不适合 window,所以我通过将 LazyColumn 封装在 Box 中并设置了 horizontalScroll() 修饰符,使 LazyColumn 可以水平滚动。

现在 LazyColumn 也可以水平滚动了。但奇怪的是 Divider 分隔项目的部分消失了。

深入研究一段时间后,我发现 Divider 仅在放置在可水平滚动的父对象中时才变得不可见。


最小复制

这里是观察到的行为的最小再现,其中红色 Divider 显然 不可见 horizontalScroll(rememberScrollState()) 修饰符设置在 Box 中时。

fun main() = application {
    Window(onCloseRequest = ::exitApplication) {
        Box(
            Modifier.fillMaxSize()
                .background(Color.Green)
                .horizontalScroll(rememberScrollState())
        ) {
            Divider(thickness = 10.dp, color = Color.Red)
        }
    }
}

可以看出红色Divider对于上面的代码不可见


预期输出:

使用 verticalScroll() 或完全不使用滚动修饰符都可以正常工作。

fun main() = application {
    Window(onCloseRequest = ::exitApplication) {
        Box(
            Modifier.fillMaxSize()
                .background(Color.Green)
                .verticalScroll(rememberScrollState())
        ) {
            Divider(thickness = 10.dp, color = Color.Red)
        }
    }
}

如预期的正确输出,对于上面的代码,红色 Divider 显然 可见


版本信息

kotlin("jvm") version "1.5.21"
id("org.jetbrains.compose") version "1.0.0-alpha3"

我想知道这是否是一个错误?或者有什么办法可以解决这个问题。

,这不是错误。

Divider 用于占满宽度,就像使用 fillMaxWidth() 修饰符的任何其他视图一样。

但是在horizontalScroll里面这个修饰符被忽略了,因为它是有歧义的:horizontalScroll包裹了内容的大小,所以maxWidth这个区域的约束是无限的。

来自 fillMaxWidth documentation:

If the incoming maximum width is Constraints.Infinity this modifier will have no effect.

我没有找到任何文档提到horizontalScroll影响Constraints,你可以在same issue上看到维护者的回答,或者你可以自己测试它:

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}")
    }
}

在这种情况下,您需要明确指定宽度,例如:

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)
            )
        }
    }
}

请注意,当您的 LazyColumn 的顶部小于底部时,如我的示例,宽度一开始会变小(以仅容纳可见部分),但向下滚动后并备份,宽度不会恢复到原来的宽度,因为 Divider 宽度修饰符不会让它缩小。如果需要防止这种情况,需要只根据可见元素计算'width',比较复杂。