49

I am creating a Jetpack Compose Dialog that contains a Column where all of the elements should always be visible, except for the third element, which is a Text that should be scrollable if the text doesn't fit the screen space. I almost achieved this with a secondary scrollable Column just for that Text element. However, this implementation pushes the bottom child (a button) out of view if there is a lot of text. Here is my code:

@Composable
fun WelcomeView(
    viewModel: WelcomeViewModel,
    onDismiss: () -> Unit
) {
    Dialog(onDismissRequest = onDismiss) {
        Box(
            modifier = Modifier
                .clip(RoundedCornerShape(Spacing.extraLarge))
                .background(Colors.backgroundBase)
                .padding(all = Spacing.medium)
        ) {
            Column {
                IconView(
                    name = IconViewNames.RUNNING_SHOE,
                    size = IconViewSizes.LARGE,
                    color = Colors.primaryBase
                )

                Text(
                    viewModel.title,
                    style = Text.themeBillboard,
                    modifier = Modifier.padding(bottom = Spacing.medium)
                )

                Column(
                    modifier = Modifier
                        .verticalScroll(rememberScrollState())
                ) {
                    Text(
                        viewModel.message,
                        style = Text.themeHeadline,
                        modifier = Modifier.padding(bottom = Spacing.medium)
                    )
                }

                Button(
                    onClick = onDismiss,
                    modifier = Modifier
                        .fillMaxWidth()
                        .clip(RoundedCornerShape(Spacing.medium))
                        .background(Colors.primaryBase)
                ) {
                    Text(
                        "Continue",
                        style = Text.themeHeadline.copy(color = textExtraLight),
                        modifier = Modifier.padding(all = Spacing.extraSmall)
                    )
                }
            }
        }
    }
}

@Preview
@Composable
fun PreviewWelcomeView() {
    WelcomeView(
        viewModel = WelcomeViewModel(
            firstName = "Wendy",
            htmlWelcomeMessage = PreviewTextFixtures.threeParagraphs
        ),
        onDismiss = {}
    )
}

This is what it (correctly) looks like when there is only one paragraph of text:

enter image description here

But this is what it looks like when there are three paragraphs. The text scrolls correctly, but notice the missing "Continue" button:

enter image description here

Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
Eugene
  • 3,417
  • 5
  • 25
  • 49

2 Answers2

105

Use this for your middle (scrollable) composable

    Column(
        modifier = Modifier
            .verticalScroll(rememberScrollState())
            .weight(weight =1f, fill = false)

    ) {
        Text("Your text here")
    }

The key is to use fill = false.

Francesc
  • 25,014
  • 10
  • 66
  • 84
37

Just apply to the scrollable Column the weight modifier.
Something like:

    Column (verticalArrangement= Arrangement.SpaceBetween) {
            Text(
                "viewModel.title",
            )

            Column(
                modifier = Modifier
                    .verticalScroll(rememberScrollState())
                    .weight(1f, false)

            ) {
                Text("...")
            }

            Button() 
            
        }
Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
  • 2
    Oh wow that's exactly what I was looking for, thank you! – Eugene Jun 28 '21 at 14:39
  • 1
    Actually when I add this, it looks correct if I have a large amount of text, but for a small amount of text, the Column still stretches out too far, expanding the parent view to maximum height and causing a visual gap between the bottom of the scrollable text and the button. – Eugene Jun 28 '21 at 14:48