I have a button with conditional content: `Circula...
# compose
l
I have a button with conditional content:
CircularProgressIndicator
and
Text
. I want the button to stay the same size across content changes. This is easy enough if we just convert the text size in
Sp
to
Dp
and set the
CircularProgressIndicator
’s size padding accordingly. However, when we consider that the text may become multiple lines when font size is increased for accessibility this solution no longer works. I am considering building a
SubcomposeLayout
implementation that measures the
Text
and sets the button height accordingly and then can conditionally forego placing the
Text
. This seems a little computationally expensive. I don’t think
Intrinsics
will solve my problem. Does anyone have a suggestion for me before I build out my abstract
SubcomposeLayout
solution?
1
f
I would go with intrinsics. Provided one dimension is set (like the width), you can calculate how tall each child composable wants to be and choose the largest of the set, then build a set of
Constraints.fixed(width = constraints.maxWidth, height = max(all children height))
then lay one child or the other based on your logic
Subcompose is more specific and comes with a performance penalty, if you can get away with intrinsics that's the better solution
l
Right…
I haven’t done much with intrinsics
so you are still saying build a custom
Layout
, right?
f
if you don't know how much space you are going to need ahead of time, then yes, otherwise use a
Box
to wrap both children
l
Ok so in the case of the
Box
how do you extract it’s
Intrinsic
height prior to
Composition
? For example we want to see the height of height of the
Text
here
Copy code
Box {
    Text("Intrinsics are fun")
}
f
you would use a
Box
(or
CrossFade
) if your height is fixed. If not, use a layout, then use the measure the required height use
maxIntrinsicHeight
for each composable, then use the max of those heights to set the actual height of the
Layout
. See this https://developer.android.com/jetpack/compose/layouts/intrinsic-measurements#intrinsics-in-layouts
l
The issue came up because the height must change with accessibility 🤔 so it is fixed in
Sp
f
I have to run, but you could check this out where I use intrinsyc widths to ensure the children are all of the same width, similar to what you are after (but you seem to be after height, though the principle is the same) https://github.com/fvilarino/Weather-Sample/blob/c7e0916d4311c5ff5f3fc5cf620484957[…]ncescsoftware/weathersample/shared/composable/EqualSizeTiles.kt
l
Cheers man
you are a hero
a
I could for sure see myself using
alpha
on the
Text
as a simple hack… probably doesn’t satiate you, but nobody has to know 😸
l
You are the devil in my ear 😉
@Francesc I would be interested to hear how you would forego placing one of your tiles in that example. That is really the hardest part. Because I would need to enter both the
Text
and the
CircularProgressIndicator
into the
Layout
, measure them, and then withhold placement of one or the other. It seems difficult to do this robustly using
Intrinsics
.
tLeaning further and further towards
Heavily considering making a deal with the devil 😈
a
then can conditionally forego placing
That’s probably the cleanest solution, and no need to use
SubcomposeLayout
or anything!
You can conditionally not call
place
by passing a
Modifier
to the component you want to take up space, but don’t show:
Copy code
Modifier.layout {
    val placeable = measurable.measure(constraints)
    layout(placeable.measuredWidth, placeable.measuredHeight) {
        if (showProgressIndicator) {
            placeable.place(0, 0)
        }
    }
}
l
It seems I haven’t been taking full advantage of `Modifier`s. 😻 That is indeed as clean as it comes.
I just knew I would brush genius here 👼
a
Although it looks like there’s a bug with that right now… https://kotlinlang.slack.com/archives/CJLTWPH7S/p1672839190220699 So you might need to do something like
Copy code
if (showProgressIndicator) {
    Modifier
} else {
    Modifier.layout {
        val placeable = measurable.measure(constraints)
        layout(placeable.measuredWidth, placeable.measuredHeight) {}
    }
}
l
You have saved me a lot of time and effort, for that I thank you 🫶
a
Issue you can track for having something like this built-in: https://issuetracker.google.com/issues/158837937
l
🐐 ☝️
Worked exactly how I expected! Thanks again @Alex Vanyo
102 Views