I'm having trouble with this modifier that I've ha...
# compose
c
I'm having trouble with this modifier that I've had in my codebase for a long time in production. It seems like I was relying on onSizeChanged to only be called once but now it's being called multiple times with the same value. This keeps on growing the value of totalSize until the app crashes (Crash:`Can't represent a size of 262368 in Constraints`)
Copy code
Modifier.onSizeChanged {
        Log.e("DEBUG", "height: ${it.height} and totalHeight: $totalSize")
        totalSize += it.height
}
E/DEBUG: height: 340 and totalHeight: 340 E/DEBUG: height: 340 and totalHeight: 680 E/DEBUG: height: 340 and totalHeight: 1020 ... then crashes All I'm trying to do is fine the height of a composable after it's been drawn so I know it's height in pixels. I'm confused because this wasn't happening in the past, but it seems like in alpha2 or alpha3 something changed?
f
The documentation is pretty explicit about this:
Invoked with the size of the modified Compose UI element when the element is first measured or when the size of the element changes.
There are no guarantees
onSizeChanged
will not be re-invoked with the same size.
c
Guess it worked for a while depending on the fact that it wouldn't be reinvoked. is there some other approach you recommend by chance?
onSizeChanged, onGloballyPositioned BoxWithConstraints oh my!
f
The issue with your code is that you're adding the value so you're susceptible to overrun
or a better way to say it is that you are dependent on an implementation detail of the API you're using
c
yeah. i think i'm just going to do something kinda clunky now and just save a
gotAHeightValueAlready = false
and set it to true when I get a value for now. I know that the height isn't changing once itst laid out, but I guess I will try to find a more permanent fix for this.
f
I don't know the specific details of your scenario, but apps can change size due to rotation, split mode or resizing (on chromebooks, for instance), so that's something to keep in mind as the value you read may not be valid later on
j
This behavior changed a bit ago: https://android-review.googlesource.com/c/platform/frameworks/support/+/1708420 Why do you want to add to the
totalSize
? The size you get from
onSizeChanged
is absolute
c
Basically I have a LazyColumn and I'm implementing a parralax effect with an image behind the LazyColumn. What I'm doing in the modifier is adding the heights of the first two items in the lazyColumn together and setting that to the height of the image. The example I showed here is simplified, but I'm pretty much just checking if index == 0 or index == 1 and then grabbing those and adding it to the total. Then total is used for the height of the image. 😄
Let me know if there's some better way to do it.
f
You could try to use the LazyListState and get the offset of the third item, that's the height of the first two items. You'd need to check that the first item offset is 0 so the list is not scrolled when you get this value
This is fragile though
c
Gotcha. I tried using lazyListState for another thing I implemented a few weeks ago and had a few issues with it. I'm going to ship my hack around this to prod right now so we don't crash, but I'll experiment with the above.
b
Quickly hacked together but something like this maybe?
Copy code
val heights = remember { mutableStateListOf(0, 0) }
    val totalHeight = heights.sum()

    Text("$totalHeight")
    LazyColumn {
        itemsIndexed(snacks) { index, snack ->
            SnackItem(
                snack,
                onSnackClick,
                Modifier.onSizeChanged {
                    if (index <= 1) {
                        heights[index] = it.height
                    }
                }
            )
        }
    }
c
Will give this a shot today. Thanks for taking your time to help!
@Ben Trengrove [G] that worked! and... so much better than my impl! Thanks Ben!
120 Views