https://kotlinlang.org logo
Title
a

Alexander Maryanovsky

03/20/2023, 9:26 AM
Why doesn’t the inner box fill the outer box? Screenshot in thread
@Composable
private fun MyLayout(){
    Box(Modifier.fillMaxSize().background(Color.Yellow)){
        Box(modifier = Modifier
            .background(Color.DarkGray)
            .sizeIn(minWidth = 200.dp, minHeight = 200.dp)
        ) {
            Text("BOX", modifier = Modifier.align(Alignment.Center))
        }
    }
}
Screenshot_1679304349.png
o

Oleksandr Balan

03/20/2023, 9:29 AM
The
Box
composable has
propagateMinConstraints
argument, which is set to
false
by default. Thus min constraints from the outer box are not automatically provided to the inner box. Try setting
propagateMinConstraints = true
for outer box.
l

Laurynas Mykolaitis

03/20/2023, 9:31 AM
Inner box is not set to fill it? Unless I misunderstood the question. Instead of .sizeIn use
Modifier
    .fillMaxSize()
a

Alexander Maryanovsky

03/20/2023, 10:05 AM
@Oleksandr Balan That did it, thanks!
Something about the compose layout system is counter-intuitive, but I can’t quite put my finger on it yet.
s

Stylianos Gakis

03/20/2023, 10:48 AM
propagateMinConstraints
is a big part about this I think. Once I realized
Surface
turns this to true by default (not configurable) I realized why I was confused about why sometimes it’d automatically make the child match the parent size and why some other times (where I was not using
surface
) it would not. This, along with the ability to sometimes not listen to the parent constraints, and are able to break from them (for good reason) were the two things that have made me question my understanding the most. But after you figure those out I think it gets easier.
a

Alexander Maryanovsky

03/20/2023, 10:55 AM
I think maybe I have to stop thinking of it in terms of the names of the modifiers, and instead to just think about what they actually do. For example, what
fillMaxSize()
does is set the
minWidth
to
maxWidth
and
minHeight
to
maxHeight
of the incoming Constraints.
s

Stylianos Gakis

03/20/2023, 10:56 AM
Yes ^^ this is also super important to internalize, you are right.
a

Alexander Maryanovsky

03/20/2023, 10:56 AM
and
sizeIn(minWidth=X)
just sets the
minWidth
of the incoming Constraints to
X
So with
Box(
        modifier = Modifier.fillMaxSize().background(Color.Yellow),
        propagateMinConstraints = true
    ){
        Box(modifier = Modifier
            .background(Color.DarkGray)
            .sizeIn(minWidth = 200.dp, minHeight = 200.dp)
        ) {
            Text("BOX", modifier = Modifier.align(Alignment.Center))
        }
    }
The incoming Constraints of the inner box are
(minWidth=200.dp, minHeight=200.dp, maxWidth=activityWidth, maxHeight=activityHeight)
and there’s nothing that asks it to fill the activity
But with
propagateMinConstraints = true
, the incoming constraints are
minWidth=activityWidth,
minHeight=activityHeight,
maxWidth=activityWidth,
maxHeight=activityHeight
because those are the constraints of the outer box
s

Stylianos Gakis

03/20/2023, 4:42 PM
Ha! And just as we’ve had this conversation today, I noticed another thing which was initially odd regarding using Surface and
propagateMinConstraints
. I was using the
Card
composable, which uses a
Surface
under the hood, so I was expecting the min constraints to be propagated. However, if you notice inside the card composable, it wraps the content in a Column (no idea why a column in particular), which actually meant that this column is the one which gets the min constraints to be as big as the card itself, however the content of the column does not get that! Meaning that as I was trying to get the card content to align at the center vertically, I couldn’t do that. I have to instead either make my own card composable which does not wrap its content with any other composable which does not propagate min constraints, or align the content itself by using the fact that I am inside a
ColumnScope
Hmm this may not even be possible actually and I might have to make my own Card composable which propagates min constraints to achieve centering the content inside the card no matter the height, since Card does not allow one to pass in a
verticalArrangement
for its content. What an interesting thing, I really do wonder why it was done this way for the Card implementation tbh. Maybe as a sane default when people put many things inside the card content 🤷‍♂️
Wrote this https://issuetracker.google.com/issues/274389472, let’s see what the idea is and how should one be able to achieve this actually without re-creating the Card composable itself
z

Zach Klippenstein (he/him) [MOD]

03/21/2023, 3:32 PM
Column and Row not propagating min constraints on their cross axis by default is probably one of my least favorite things about compose. I think I saw on here a couple years ago that the team regrets that decision as well but it’s too late to change it now
a

Alexander Maryanovsky

03/21/2023, 3:33 PM
There’s always
Column2
😉
s

Stylianos Gakis

03/21/2023, 3:38 PM
Aside from column/row, I really do wonder why Card also does the same, the more I think about this the more I wonder. In fact, since yesterday where I introduced this Card2 (sorta) which just doesn’t use a Column under the hood but calls the composable as it is under the Surface which propagates the min constratints, I realize that at every other point I was calling this Card of mine I was doing some workaround (Usually
fillMaxSize()
) in order to work around the issue with the inner content not being the same size as the card where I’ve literally just set as
Size(x.dp)
. I can now remove these workarounds by using my custom card.
j

Jan Skrasek

03/21/2023, 6:49 PM
Column and Row not propagating min constraints on their cross axis by default is probably one of my least favorite things about compose. I think I saw on here a couple years ago that the team regrets that decision as well but it’s too late to change it now
The issue here is that there is no such argument to change this on Column or Row. I have implemented a custom simple Column for this two times already.
z

Zach Klippenstein (he/him) [MOD]

03/21/2023, 8:58 PM
I don’t think it should be an parameter even. A column (vertical) should not have any opinions about horizontal layout at all and should always pass horizontal constraints through, in my opinion. The current behavior could then be achieved by passing a wrapContentWidth modifier.
s

Stylianos Gakis

03/21/2023, 9:11 PM
It's definitely too late to make this happen right? Or are such behavior changes something that the compose team is willing to do if it means improving usability? This doesn't break compatibility in any way, but would definitely "break" some clients who upgrade without checking for these changes meaning that the resulting UI will be different, not that it will crash.
z

Zach Klippenstein (he/him) [MOD]

03/21/2023, 11:13 PM
Correct, it would be a significant behavior change so we wouldn’t make it at this point
s

Stylianos Gakis

03/21/2023, 11:14 PM
Suddenly Column2 doesn’t sound like such a crazy idea
a

Alexander Maryanovsky

03/22/2023, 10:51 AM
So I’m still left with a question. How to arrange a layout that says 1. My minimum/preferred size is X*Y 2. If I’m given more, I will fill it. Specifically, I’m having trouble allowing the very common desktop use-case of having a window open at the content’s preferred size, but then grow bigger (maybe smaller too) if the user resizes the window.
aka
Window.pack()
in AWT terms