7

I just created a simple Composable and wished to render it using a Layout, but while implementing the solution, I stumbled upon this error in the measurement phase.

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)

This was when I tried this

val sampleComposable = measurables[1].measure(
                Constraints(
                    minHeight = constraints.maxHeight * 7 / 10,
                )
            )

Anyone stumble upon this before? What's the solution if it is not a bug, in which case please let me know.

Now, the issue here I think is the fact that I am nesting two Layout Composables,

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

Where The nestedLayoutComposable again has a Layout and that is where the crash occurs, it is at this line

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

So I know that the issue is with the Layout Composable being nested within one another but that still doesn't explain WHY the error occurs, and HOW to resolve it, and so those are the prime queries of this post, and that is what I expect the answers to include, thank you.

Richard Onslow Roper
  • 5,477
  • 2
  • 11
  • 42
  • Interesting.... the only hint I can give is..... It looks like the tool is using signed 32 bit numbers instead of unsigned. In the function call giving you grief consider scaling by 9/10 instead of 90/100 (the multiply by 90 may be aggravating an overflow). – J. R. Schweitzer Mar 08 '22 at 19:52
  • @Mark what exactly am I to take away from this? – Richard Onslow Roper Mar 08 '22 at 20:13
  • @J.R.Schweitzer I tried that but it still gives the same error which actually makes sense, since even if the constraints "store" the numbers in a representation of their own, the assignment (or storage) phase would not be triggered till the calculation is complete, which means that I can literally deal in numbers ranging to billions and it would still never matter if by the end I have reasonable values. – Richard Onslow Roper Mar 08 '22 at 20:23
  • It works every time, the problem seems to be because of nesting it. So, I'm pretty sure the measurement method is not the issue, sir. Thanks for the input though, appreciate it. – Richard Onslow Roper Mar 08 '22 at 20:40
  • I seem to be having a similar issue. My layout measurements work fine when they're 1-2 deep, but anything other than that I get `Can't represent a size of 214748364 in Constraints` as well. Did you get anywhere with this by any chance? @MARSK – Gabriel Ferreira Apr 20 '22 at 16:32
  • 1
    I came across this when adding a `ComposeView` inside a layout contained by a `NestedScrollView`. The composable view started with a `Column` - my guess is the scrollable column was interacting with the scrollable container - of that the scrollable container has an infinite size, resulting in this error we both saw. – Richard Le Mesurier May 25 '22 at 15:50
  • @RichardLeMesurier did you make any fix for this issue? Seems like I'm having the same error. – Viks Jun 28 '22 at 01:11
  • No I went with my guess and removed that scrollable `Column` from the layout. – Richard Le Mesurier Jun 28 '22 at 17:26
  • I get this error when adding a `verticalScroll` modifier to a non-nested `VerticalScollbar`, which is probably a stupid thing to do. – rwst Apr 29 '23 at 15:30

5 Answers5

2

In my case similar crash was caused by scrollable Column inside another scrollable Column. Check if you do not have such a case in your compose hierarchy.

Coldnight
  • 107
  • 13
  • While it does provide a correlation between scrollable columns and the problem, it does not, unfortunately, provide a solution or a workaround to the problem. If a design requires scrollable columns, it would not be ideal to change the design because it is, in fact, possible to nest scrollables in Compose. – Richard Onslow Roper Oct 19 '22 at 12:56
1

For anyone else that comes across this, the problems is that scrollable views set maxHeight to Constraints.Infinity, which is represented as Int.MAX_VALUE. So if your layout assumes a bounded height, it's going to overflow the int value.

frodo2975
  • 10,340
  • 3
  • 34
  • 41
0

This basically happens when you jam much more than the composable has room for to display.

I have reproduced it using a very long String for a List item

Cyber Avater
  • 1,494
  • 2
  • 9
  • 25
0

This happened to me when I tried to use a Slider inside a Column that had Modifier.width(IntrinsicSize.Min), no matter whether the column is its direct parent or not. Though the exception disappears when I use another overload of the slider where you provide a lambda to the thumb parameter but this time the slider doesn't have a thumb. The exception also disappears when I specify a fixed width on the slider.

It's a bug.

Edit: fixed, just needed to update libs.

Edit 2: the libraries were:

  • org.jetbrains.kotlin:kotlin-bom, updated from 1.8.0 to 1.9.0
  • androidx.compose:compose-bom, updated from 2022.10.00 to 2023.06.01 and the respective androidTestImplementation though I don't think the latter was necessary since I didn't write tests

The minimum SDK version was 31

user128440
  • 179
  • 2
  • 7
0

In your case it's because you can't measure anything with multipliers of Constraints.Infinity. Because in source code of createConstraints function

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

converts heightVal to 0 when passed height is Constraints.Infinity when you modify it you send a value to bitsNeedForSize that overflows maxrange and it crashes with

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

Simple check should be whether the dimension you use is Constraints.Infinity using hasBoundedHeight or constraints.min/maxHieght == Constraints.Infinity

Also another check should be for min constraints not being bigger than maxConstraints so

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

)

using such a Constraints to measure your content Composables won't crash.

Also to set your custom layout height if it has a Modifier.fillMaxHeight() or Modifier.height(100) by checking hasFixedHeight and not a infinite with hasBoundedHeight

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

When it doesn't have a size Modifier or a Modifier with Modifier.height(min=0.dp, max=500.dp)

you say let this Composable as big as content but within range of Constraints from size Modifier.

This check also makes sure your Composable do not crash when intrinsic height modifier is assigned.

java.lang.IllegalArgumentException: Can't represent a size of 2147483647 in Constraints
Thracian
  • 43,021
  • 16
  • 133
  • 222