为什么 .width() 和 .height() 修饰符应用错误的值?

Why .width() and .height() modifiers apply wrong value?

我希望两个 独立 行具有相同的宽度并同时滚动。我试图通过这种方式实现这一目标:

@Composable
fun TwoRows() {
    val scrollState = rememberScrollState()

    Column(Modifier.fillMaxWidth()) {
        Row(Modifier.fillMaxWidth().horizontalScroll(scrollState)) {
            for (i in 0 until 100) {
                Box(Modifier.width(10.dp).height(10.dp).background(Color.Red))
                Spacer(Modifier.width(90.dp))
            }
        }
        Row(Modifier.fillMaxWidth().horizontalScroll(scrollState)) {
            for (i in 0 until 100) {
                Box(Modifier.width(100.dp).height(10.dp).background(Color.Green))
            }
        }
    }
}

第一行由 10 dp 宽度的红色矩形和 90 dp 宽度的间隔符组成。第二行仅包含 100 dp 宽度的绿色矩形。我希望这些行具有相同的宽度,但布局检查器显示它们不是:

因此元素与预期位置不匹配:

我该如何解决?

发生这种情况是因为 .size()width().height() 修饰符中的每一个都将传入值转换为像素 恰好应用了 。 IE。它们独立应用 - 第一个修饰符将其值转换为像素,然后是第二个,依此类推。由于四舍五入,无法保证在将 dp 值转换为 px 并返回后获得相同的 dp 值。以下是 dp->px->dp 转换如何适用于您的情况:

dp = 10.dp // Incoming dp value
density = 2.625 // Screen density scale value of your emulator
unrounded_px = 10 * density = 26.25
px = 26
restored_dp = 26 / density = 9.904762.dp

很可能 LayoutInspector 没有将计算出的 dp 值四舍五入到最接近的整数,而是简单地丢弃了小数部分。我认为这就是它显示出不同价值的原因。当您在低像素密度屏幕上使用相对较小的视图时,这种行为特别容易发生。

您可以实现所需的行为,将红色 BoxSpacer 包装到具有指定大小的 Box 中:

Box(Modifier.width(100.dp).height(10.dp)) {
    Box(Modifier.width(10.dp).height(10.dp).background(Color.Red))
    Spacer(Modifier.width(90.dp))
}