无法在约束条件中表示大小为214748364

10

我刚刚创建了一个简单的可组合项,并希望使用 Layout 渲染它,但在实现解决方案时,在测量阶段我遇到了这个错误。

java.lang.IllegalArgumentException: Can't represent a size of 214748364 in Constraints
        at androidx.compose.ui.unit.Constraints$Companion.bitsNeedForSize(Constraints.kt:408)
        at androidx.compose.ui.unit.Constraints$Companion.createConstraints-Zbe2FdA$ui_unit_release(Constraints.kt:368)
        at androidx.compose.ui.unit.ConstraintsKt.Constraints(Constraints.kt:438)
        at androidx.compose.ui.unit.ConstraintsKt.Constraints$default(Constraints.kt:423)
        at com.gmarsk.aiare.MainActivity$InstructionsScreen$DisplayCard$1.measure-3p2s80s(MainActivity.kt:514)
        at androidx.compose.ui.node.InnerPlaceable.measure-BRTryo0(InnerPlaceable.kt:54)

这是我尝试过的时候。
val sampleComposable = measurables[1].measure(
                Constraints(
                    minHeight = constraints.maxHeight * 7 / 10,
                )
            )

有人之前遇到过这个问题吗?如果不是一个 bug 的话,解决方案是什么呢?如果是 bug,请让我知道。

现在,我认为问题在于我正在嵌套两个 Layout 组合函数,

Layout(
content = {
 Dummy1()
 Dummy2()
 NestedLayoutComposable() // It contains a Layout Composable itself
}{ measurables, constraints ->
 val nlc = measurables[2].measure(
  Constraints(
   minHeight = constraints.maxHeight * 7/10
  )
 )
 layout(constraints.maxWidth, constraints.maxHeight){
  nls.place(0, 0)
 }
}
)

嵌套布局组件再次具有Layout,这就是崩溃发生的地方,具体来说是在这一行:

            Layout(
                content = {
                    Text(text = "Random")
                    Box {
                        Image(painter = AppUtils.getRandomImagePainter(), contentDescription = "")
                    }
                }
            ) { measurables, constraints ->
                val text = measurables[0].measure(constraints)
/*This line -->*/   val image = measurables[1].measure(
                    Constraints(
                        maxWidth = constraints.maxWidth * 90 / 100,
                        minHeight = constraints.maxHeight * 7 / 10
                    )
                )

                layout(constraints.maxWidth, constraints.maxHeight) {
                    instruction.place(
                        (constraints.maxWidth - instruction.width) / 2,
                        0
                    )
                    illustration.place(
                        (constraints.maxWidth - illustration.width) / 2,
                        illustration.height / 2
                    )
                }
            }

我知道问题出在嵌套的Layout Composable上,但这并不能解释为什么会出现错误,以及如何解决它,这就是本文的主要问题,我希望答案能包含这些信息,谢谢。


@Mark,我应该从中得出什么? - Richard Onslow Roper
@J.R.Schweitzer 我试过了,但它仍然会给出相同的错误,这其实是有道理的,因为即使约束条件“存储”数字在它们自己的表示中,分配(或存储)阶段也不会被触发,直到计算完成,这意味着我可以处理数十亿的数字,最终如果我有合理的值,那么这些数字就不会有任何影响。 - Richard Onslow Roper
1
当我在一个NestedScrollView包含的布局中添加一个ComposeView时,我遇到了这个问题。可组合视图以Column开头 - 我猜可滚动列与可滚动容器交互 - 可滚动容器具有无限大小,导致我们都看到了这个错误。 - Richard Le Mesurier
@RichardLeMesurier 你对这个问题做了任何修复吗?看起来我也遇到了同样的错误。 - Viks
当我将 verticalScroll 修饰符添加到非嵌套的 VerticalScrollbar 上时,会出现这个错误,这可能是一个愚蠢的行为。 - rwst
显示剩余4条评论
5个回答

4
在我的情况下,类似的崩溃是由一个可滚动的列(Column)内部包含另一个可滚动的列(Column)引起的。请检查您的Compose层次结构中是否有这样的情况。

1
虽然它确实提供了可滚动列与问题之间的相关性,但不幸的是,它并没有提供解决方案或解决问题的方法。如果设计需要可滚动列,则更改设计并不理想,因为实际上可以在Compose中嵌套可滚动项。 - Richard Onslow Roper

3
在你的情况下,这是因为你无法使用Constraints.Infinity的倍数来测量任何东西。因为在createConstraints函数的源代码中。
 internal fun createConstraints(
        minWidth: Int,
        maxWidth: Int,
        minHeight: Int,
        maxHeight: Int
    ): Constraints {

        //  Because of this check and bitsNeedForSize
      
        val heightVal = if (maxHeight == Infinity) minHeight else maxHeight
        val heightBits = bitsNeedForSize(heightVal)

        val widthVal = if (maxWidth == Infinity) minWidth else maxWidth
        val widthBits = bitsNeedForSize(widthVal)
}

将传入的高度为Constraints.Infinity时,将heightVal转换为0,当您修改它时,会向bitsNeedForSize发送一个超过最大范围的值,导致崩溃。
    private fun bitsNeedForSize(size: Int): Int {
        return when {
            size < MaxNonFocusMask -> MaxNonFocusBits
            size < MinNonFocusMask -> MinNonFocusBits
            size < MinFocusMask -> MinFocusBits
            size < MaxFocusMask -> MaxFocusBits
            else -> throw IllegalArgumentException(
                "Can't represent a size of $size in " +
                    "Constraints"
            )
        }
    }

简单的检查应该是您使用的维度是否为Constraints.Infinity,使用hasBoundedHeight或constraints.min/maxHieght == Constraints.Infinity

另外一个检查应该是确保最小约束不大于最大约束

val wrappedConstraints = constraints.copy(
    minHeight = if (constraints.hasBoundedHeight)
        (constraints.maxHeight * 7 / 10).coerceAtMost(constraints.maxHeight)
    else 0,

)

使用这样的约束来测量您的内容组件将不会崩溃。

此外,通过检查是否具有固定高度(hasFixedHeight)而不是无限高度(hasBoundedHeight),可以设置自定义布局的高度,例如 Modifier.fillMaxHeight() 或 Modifier.height(100)。

  val contentHeight = // This some height you get with max, sum or your logic

  val totalHeight = if(hasBoundedHeight && hasFixedHeight){
        constraints.maxHeight
    }else {
        contentHeight.coerceIn(constraints.minHeight.toFloat(), constraints.maxHeight.toFloat())
    }

当它没有大小修饰符或带有Modifier.height(min=0.dp, max=500.dp)的修饰符时,你说让这个可组合项与内容一样大,但在大小修饰符的约束范围内。
这个检查还确保当分配了内在高度修饰符时,你的可组合项不会崩溃。
java.lang.IllegalArgumentException: Can't represent a size of 2147483647 in Constraints

2
这是我在尝试在一个具有Modifier.width(IntrinsicSize.Min)Column内部使用Slider时遇到的问题,无论该列是否为其直接父级。当我使用另一种重载的滑块,其中您为thumb参数提供了一个lambda表达式时,异常就会消失,但这次滑块没有拇指。当我在滑块上指定一个固定的宽度时,异常也会消失。
这是一个bug。
编辑:已修复,只需更新库。
编辑2:以下是所使用的库:
- org.jetbrains.kotlin:kotlin-bom,从1.8.0更新到1.9.0 - androidx.compose:compose-bom,从2022.10.00更新到2023.06.01以及相应的androidTestImplementation,尽管我不认为后者是必要的,因为我没有编写测试。
最低SDK版本为31。

你能提供你必须更新的软件包来修复这个错误吗?还有可能提供最低版本吗? - tsalaroth

2
对于其他遇到这个问题的人,原因在于可滚动视图将 maxHeight 设置为 Constraints.Infinity,表示为 Int.MAX_VALUE。因此,如果您的布局假定高度是有界的,它将溢出 int 值。

1
这基本上是发生在你塞进去的内容超过了可显示的空间。
我使用一个非常长的字符串来重现它作为列表项。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接