Is there a way to have a column with 2 items A and...
# compose
t
Is there a way to have a column with 2 items A and B. And have item A grows to as much size as needed up to B having enough space for it's whole content. Putting weight to B does not work as A can expand more, and putting weight on both have the weight values prioritized over the side of the content itself. Seems the column measure in order so A "wins"
a
I tried this some time ago and it was difficult. Eventually I used onGloballyPositioned, but I think a custom layout would be better: https://kotlinlang.slack.com/archives/CJLTWPH7S/p1669144959297069
t
Thanks, yes I think I'll have to go the custom layout 😞
e
I’m not sure you need a custom layout. Can you expatiate on the question a bit more, its hard for me to understand ypur requirement
(maybe add a screen shot of the design if you have)
t
In a screen to simplify I need 2 sub part. A and B. A can grow up to a ratio of 1. To simplify let's say B have a fixed height. I need B to be fully visible with A to take the rest of the space when constrained. Or A to grow up to it's ratio and B have the rest.
e
Okay
weight() has a
fill
parameter, if you set that to false then it will let A grow
t
Yes but no it does not work here 😞
The goal is to handle that screen for the strange ratio on some phones and very large font sizes.
e
Which part is A and which is B? I guess the album art is A and the rest is B.
Seems like you need multiple levels (based on priority of the ui elements)
t
I think with custom layout I can handle this. First pass measure, if both fit then A and rest of size to B, else remeasure A with constraints updated to take B in account.
I don't think I can do that without 2 measures.
e
Album art would be aspectRatio(1f), rest of the space goes to B. Now B is its own column with its own arrangement. Within B, whatever are the important elements must be given fixed constraints or measured at their size, the less important parts will have weight(Xf)
Isnt the album art supposed to be always square? Because if not then what you described should work (using SubcomposeLayout)
t
Yes it is unless the phone aspect ratio causes issue and prevent B to be displayed.
Like on a square screen to go the absurd case.
In that case B should be displayed and A have whatever is left.
And inside A I can center a ratio(1) image so keep the image correct just smaller.
e
Seems a custom layout will nail this.
t
Yep just need to find some example about how update the constraints for the second measure.
e
You dont need to do that
You should measure B with its intrinsic size
t
Yes but if there's more space B should take more than it's intrinsic, I suppose I need to remeasure to pass the info to the custom layout as in views no?
e
So B will be a Column that wraps BUT it will have two spacers (weight 1f each) around the play button. That way if there is enough space within the constraints, those spacers will distribute it or else they will be zero height
Then the custom layout should get B’s intrinsic height (which ideally should mean those spacers have 0 height, not sure this part is as straightforward) Using B’s intrinsic you compare with A’s, if they fit within max height, perfect, measure & place both normally If they don’t fit, measure A with (maxHeight - B’s intrinsic) & B with its intrinsic height as constraint, then place them
t
(which ideally should mean those spacers have 0 height, not sure this part is as straightforward)
e
I wouldve tried to post an example but I am not at PC atm
t
That's the part I had issues with if I play with weight then intrinsics become infinite 😞
e
Ah of course
t
If not and I play with verticalAlign then broken too.
e
Try setting IntrinsicSize.Min on both spacers (I am only guessing here, I will need to try it out myself)
t
Thanks will try to do more tests when I have time, just need to find some good doc about custom layout measurements as the official page is quite lightweight on it
e
Yeah for custom layouting the javadocs are actually pretty good and the API surface is small enough so you can browse it and get some idea. The entry points are usually
Layout
,
SubcomposeLayout
&/or
Modifier.layout
player.kt
And the preview:
t
Wow thanks a lot, did not know it's already Christmas. I got people at home right now, but will test ASAP.
e
You welcome, I learned something new myself!
t
Just did a quick test and it crash as some of my attempts 😞
Copy code
java.lang.IllegalStateException: Asking for intrinsic measurements of SubcomposeLayout layouts is not supported. This includes components that are built on top of SubcomposeLayout, such as lazy lists, BoxWithConstraints, TabRow, etc. To mitigate this:
                                                                             - if intrinsic measurements are used to achieve 'match parent' sizing,, consider replacing the parent of the component with a custom layout which controls the order in which children are measured, making intrinsic measurement not needed
                                                                             - adding a size modifier to the component, in order to fast return the queried intrinsic measurement.
Probably because the view is used inside a BottomSheetScaffold
e
I'm not sure that is it. You cannot request intrinsic size for a child based on subcompose layout. But we don't have any subcompose layout children here.
Just confirming, the bottom sheet scaffold wraps this player layout right?
And your A & B layouts are not subcomposeLayout nodes?
t
In A there's a Pager and in B a constraintbox at some level for the slider.
e
Ah yeah give the slider a height like in my example
t
Ok so removing most of things does fix so yes it's about the children. Seems there's more cases I also have a custom marquee text (but the compose one is also a subcompose)
The pager will be an issue too.
e
Ah damnit. Probably need to try another approach
You can use subcompose instead and then measure it twice, but I haven’t tried that
t
when tested quickly after your first comment I had the same kind of crash during measure. But thanks a lot I have a better vision of the measure and stuff and know what is the issue.
I'll see if I can workaround.
Well no way I can workaround the pager being a lazylist 😞
a
I didn't read your conversations but simply setting
Modifier.weight(1f, fill = false)
on A seems enough to solve the problem.
t
No it's not, It's discussed earlier 😞 The preview from @efemoney shows the need.
The issue is that B needs to grow to fit the remaining space. As I need some of the buttons to be at the bottom and the full space used.
a
Ok I see what you want now. If you can remove subcompose layouts from B that's enough because you don't need the intrinsic size of A. You can query the intrinsic height of B, measure A with a max height constraint of
maxHeight - intrinsicHeightOfB
, and then measure B with a max height constraint of
maxHeight - heightOfA
.
t
I have a few view that use those like the custom slider and the custom marquee. Not sure it's an easy migration for me for those.
Isn't there a simple way to just measure twice ? It's forbidden in the Layout but maybe in subcompose I'll be able to do that.
a
LookaheadLayout?
t
Always associated that with animations, but from it's definition it might help yes, thanks will look into that if I can't refactor to have simpler intrinsics to work.
Ok so after fixing or removing the subcomposelayouts in B, @Albert Chang solution to fix @efemoney solutions works perfectly. Thanks both of you.