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

Kevin Hester

02/17/2020, 8:43 PM
I'm having a hard time figuring out how to have items inside a column expand to fill most of the available space. How do I say: I want the first item in the column to get most of the space, and the second item to get only a little space? I've tried LayoutSize.Min, but it seems Fill always just covers everything - rather than taking what it can get? i.e. my layout looks like:
Copy code
fun MessagesContent() {
    Column(modifier = LayoutSize.Fill) { // want to fill entire screen
        Column(modifier = LayoutSize.Fill) {             
             messages.value.forEach { // I want this list of messages to fill most of the view
                MessageCard(
                    it, modifier = LayoutPadding(
                        left = sidePad,
                        right = sidePad,
                        top = topPad,
                        bottom = topPad
                    )
                )
            }
        }

        Surface(
            modifier = LayoutPadding(8.dp) + LayoutSize.Min(40.dp, 40.dp),
            color = backgroundColor,
            shape = RoundedCornerShape(4.dp)
        ) {
            TextField(
               ...
            )
        }
    }
}
l

Louis Pullen-Freilich [G]

02/17/2020, 9:01 PM
Take a look at
LayoutFlexible
- it allows you to assign weight to something inside a row or column
k

Kevin Hester

02/17/2020, 9:11 PM
ooh that sounds perfect. thanks again. sorry to ask so many questions.
But on the emulator
If I don't include LayoutFlexible(1.0f) on the first list the list items draw properly. If I do, then all the list items are drawn on top of each other along with the item after the list.
do you want me to file a bug?
l

Louis Pullen-Freilich [G]

02/17/2020, 10:05 PM
Seems like there is a bug with the preview, and I guess there is something strange happening with your code
Could you share the whole thing after you added layout flexible?
k

Kevin Hester

02/17/2020, 10:06 PM
I'm saying the opposite. It looks correct in preview, but everything on top of each other on the actual device. Do you want a snippet of the code where I'm using layout device or do you mean my whole project? (either is fine)
also - it is interesting that on the actual device (if inside of something with FlexibleLayout) the icon's get dropped competely. But if I remove FlexibleLayout everything is good.
l

Louis Pullen-Freilich [G]

02/17/2020, 10:17 PM
Just the code for this screen, and I think it's more likely that there is a bug in the preview / the preview is using some older version and ignoring the flexible modifier than the actual device being wrong
k

Kevin Hester

02/17/2020, 10:19 PM
oh! Here you go:
Copy code
@Composable
fun MessagesContent() {
    Column(modifier = LayoutSize.Fill) {

        val sidePad = 8.dp
        val topPad = 4.dp
        
        Column(modifier = LayoutFlexible(1.0f)) {
            messages.value.forEach {
                MessageCard(
                    it, modifier = LayoutPadding(
                        left = sidePad,
                        right = sidePad,
                        top = topPad,
                        bottom = topPad
                    )
                )
            }
        }

        val message = state { "text message" }
        val backgroundColor = palette.secondary.copy(alpha = 0.12f)
        Surface(
            modifier = LayoutPadding(8.dp),
            color = backgroundColor,
            shape = RoundedCornerShape(4.dp)
        ) {
            TextField(
                value = message.value,
                onValueChange = { message.value = it },
                textStyle = TextStyle(
                    color = palette.onSecondary.copy(alpha = 0.8f)
                ),
                imeAction = ImeAction.Send,
                onImeActionPerformed = {
                    <http://MessagesState.info|MessagesState.info>("did IME action")
                    MessagesState.addMessage(
                        TextMessage(
                            "fixme",
                            message.value
                        )
                    )
                },
                modifier = LayoutPadding(4.dp)
            )
        }
    }
}
l

Louis Pullen-Freilich [G]

02/17/2020, 10:21 PM
And what are you expecting to happen? I'm not sure I follow the intention here
k

Kevin Hester

02/17/2020, 10:21 PM
I was assuming that not using LayoutFlexible on the second item (the Surface) would result in its weight being 0 (not flexible).
l

Louis Pullen-Freilich [G]

02/17/2020, 10:22 PM
/ what would you like to happen 🙂
👍 1
k

Kevin Hester

02/17/2020, 10:22 PM
The Column that contains the messages should expand to fill the view. The Surface/TextField at the bottom would stay fixed sized (and at the bottom). Essentially what you see in the screencap from the IDE.
and certainly not the odd behavior that every element in the messages list gets drawn on top of each other 😉 (MessageCard is essentially a row with two entries). When inside the FlexibleLayout on the device, it drops the first entry (see the screencap from the emulator), but if I leave off FlexibleLayout on the list it draws correctly)
l

Louis Pullen-Freilich [G]

02/17/2020, 10:26 PM
Ah I see, I missed the text field in the IDE preview. There might be some strange behaviour with having the column be flexible, kinda hard to tell. Does it work if you remove LayoutFlexible from the column, and add a
Spacer(LayoutFlexible(1f))
between the column and the surface?
k

Kevin Hester

02/17/2020, 10:26 PM
checking...
Interesting. It works better, but still not right (and different from the IDE). Here's a screencap with the code + IDE + emulator. In the IDE case, it draws the Surface at the bottom of the window (desired). On the phone with this version it no longer draws all the items on top of each other, but it is back to the same behavior I had without LayoutFlexible (the text entry box has floated back up to near the top of the screen):
l

Louis Pullen-Freilich [G]

02/17/2020, 10:35 PM
Oh, I took a look at the github link (assuming it's updated?). Looks like the preview is just calling this one function, but when you run it on the app it is inside a
VerticalScroller
, right? If you remove the scroller and other stuff, and just call this one function as the root, does it work on device?
k

Kevin Hester

02/17/2020, 10:35 PM
ooh interesting theory! checking!
Looks great now. same as on the IDE. I also just tried a quick test of just VerticalScroller (but no FlexibleLayout attached to the verticalscroller) and it seems like just a VerticaleScroller {} by itself also shows the problem. For my project I'm happy to just stop using VerticalScroller - it was left over from my doing your tutorial.
l

Louis Pullen-Freilich [G]

02/17/2020, 10:40 PM
🙂 So the issue is that flexible doesn't really do anything if it's inside a scroller. Essentially, you can think of a VerticalScroller as having infinite height, and so something 'filling' infinite space doesn't really make any sense, so we currently just treat it as wrap content, which in the case of the spacer for example just means 0 space.
k

Kevin Hester

02/17/2020, 10:40 PM
oh - that makes sense!
l

Louis Pullen-Freilich [G]

02/17/2020, 10:40 PM
So yeah, either removing the scroller or putting the text field outside the scroller so it can actually take up some space is the 'fix' here
k

Kevin Hester

02/17/2020, 10:41 PM
though does that explain why the icons disappeared on the left of each of the items when this happened?
l

Louis Pullen-Freilich [G]

02/17/2020, 10:44 PM
Uh, not sure. Could just be something like they were all being measured with 0 height as they all end up drawing on top of each other, so maybe the icon wasn't drawn
k

Kevin Hester

02/17/2020, 10:45 PM
ok sounds good. thank you for your help!