https://kotlinlang.org logo
#compose
Title
# compose
v

Vinay Gaba

03/23/2022, 8:17 PM
I was working on a custom composable using
Layout
and noticed that modifiers like weight weren't being propagated through the constraints inside the
MeasurePolicy
. I'm wondering what's the best way to handle this so I don't have to manually hardcode weight calculations when I place my composables there. Adding a code snippet in the thread.
Copy code
Layout(content = {
        leading?.let { leadingComposable ->
            Box(modifier = Modifier.layoutId("leading")) {
                this@BaseRowLayout.leadingComposable()
            }
        }
        // added a weight to this composable
        Box(modifier = Modifier.layoutId("content").weight(1f)) {
            this@BaseRowLayout.content()
        }
        trailing?.let { trailingComposable ->
            Box(modifier = Modifier.layoutId("trailing")) {
                this@BaseRowLayout.trailingComposable()
            }
        }
}) { measurables, constraints ->

   val contentMeasurable = measurables.find { it.layoutId == "content" }
}
Doing
contentMeasureable.width
here gives me the width that it occupies, however it doesn't occupy the entire available space that the weight modifier should've caused it to do so
z

Zach Klippenstein (he/him) [MOD]

03/23/2022, 8:30 PM
The
weight
modifier is an extension on `ColumnScope`/`RowScope`, it just gives a parent data to those measurables that Column/Row read to use in their internal calculations. It doesn’t do anything on layout nodes that aren’t directly children of Column/Row.
You can define your own
weight
modifiers that you can read in your own layout
But if you’re hard-coding the modifiers inside the layout’s content lambda anyway, that’s all unnecessary. Just define the weights in the measure policy based on layout ID.
so I don’t have to manually hardcode weight calculations
You’re already hard-coding these by the looks of it, just in a slightly different place
I would be happy with code that looked like this:
Copy code
// Measure leading and trailing first so we know how much space is left for content.
val leadingPlaceable = leading?.measure(constraints)
val trailingPlaceable = trailing?.measure(constraints - leadingPlaceable?.size)

// Content takes remaining space.
val contentPlaceable = 
  content.measure(constraints - leadingPlaceable?.size - trailingPlaceable?.size)
I think that still reads pretty clearly.
It looks like you’re just re-implementing Column/Row but I assume your actual layout is doing other stuff so there’s a reason for that
v

Vinay Gaba

03/23/2022, 8:53 PM
yes its more complicated and its essentially a base row, specd using the behavior prescribed by the design system
You’re already hard-coding these by the looks of it, just in a slightly different place
This was just for the example, won't always be the case. I wanted the user to have the flexibility through the composables they are passing through the slots
z

Zach Klippenstein (he/him) [MOD]

03/23/2022, 8:56 PM
So are your callers passing explicit modifiers for each of the slots?
Or do you pass a scope receiver to your slots and let them apply whatever modifiers they want to themselves?
v

Vinay Gaba

03/23/2022, 8:59 PM
Since they are slots, in theory they could use any of the modifiers. Each slot is scoped to the RowScope so the weight modifier is also available
I'm guessing the paddings don't get added to the constraints either and I'll have to add that manually? 🤔
z

Zach Klippenstein (he/him) [MOD]

03/23/2022, 9:04 PM
I don’t see any paddings in your code snippet, but
Modifier.padding
is an actual layout modifier – it has its own measure policy, reads constraints, and changes them for the modified element. That should work.
Are you creating your own implementation of
RowScope
? I’m looking at the one from
Row
and it uses a parent data class that’s internal, so you’d have to define your own.
v

Vinay Gaba

03/23/2022, 9:21 PM
I was using the one from Row itself and that's the problem I encountered - it was a private Row Parent Data class so you are right - starting to feel like I'm creating a custom row and I'm not sure if that's what I want to do 😅
the easier solution is obvious but I was trying to come up with something that can handle all my use cases. Maybe it doesn't need to be this generic
z

Zach Klippenstein (he/him) [MOD]

03/23/2022, 9:23 PM
What kind of special behavior does your design system actually require?
v

Vinay Gaba

03/23/2022, 9:24 PM
tldr; needs to make layout decisions based on available space. Easiest solution was to simply use
BoxWithConstraint
but I wanted something more performant. Some examples are trailing element overflow to the next line when its a wider screen, for some components it gets added to the content itself but below it, etc
z

Zach Klippenstein (he/him) [MOD]

03/23/2022, 9:27 PM
I guess you could just wholesale copy/paste the Row impl and change it but there's a surprising amount of code there that you'd have to maintain.
8 Views