Courtney Allen
Courtney Allen

Reputation: 11

Nesting a LazyColumn inside a scrollable Column - Jetpack Compose

I'm trying to nest a LazyColumn inside a scrollable Column in Jetpack Compose. I want the LazyColumn to vary in height with its contents until it reaches a maximum height of half the screen (in other words, the full LazyColumn is displayed unless it is larger than half the screen). I have a minimal working example using BoxWithConstraints that produces the following result for a LazyColumn containing five Row composables (each containing text and an IconButton):

Example result

There are two issues with this result:

  1. The space between the first test block and the LazyColumn is bigger than the rest of the spacing.
  2. The height of all five rows combined is less than half the height of the screen, so all of the rows should be visible, but the last row is cut off. This is because the height of the LazyColumn is calculated using the text height, and doesn't consider the height of the IconButtons, making the height of the LazyColumn too short.

Here is my code:

// composable that takes a list of strings and inserts it as a LazyColum between
// some other composables (in this case, a Row composable and two Text composables)
@Composable
fun ExampleComposable(
    stringList: List<String>,
    modifier: Modifier = Modifier
) {
    // scrollable column
    Column(
        verticalArrangement = Arrangement.spacedBy(20.dp),
        modifier = modifier
            .verticalScroll(rememberScrollState())
            .fillMaxWidth()
    ) {
        // initial Row composable
        Row(
            verticalAlignment = Alignment.CenterVertically,
            horizontalArrangement = Arrangement.SpaceBetween,
            modifier = Modifier.fillMaxWidth()
        ) {
            Text("Text before LazyColumn")
            IconButton(
                onClick = { }
            ) {
                Icon(
                    imageVector = Icons.Filled.Add,
                    contentDescription = "icon button"
                )
            }

        }
        // BoxWithConstraints to hold LazyColumn
        BoxWithConstraints {

            // measure the height of one line of text
            val textMeasurer = rememberTextMeasurer()

            val textLayoutResult = remember("Hello", TextStyle.Default, constraints) {
                textMeasurer.measure(
                    text = "hello",
                    style = TextStyle.Default,
                    constraints = constraints
                )
            }

            // get the height of the screen
            val configuration = LocalConfiguration.current
            val screenHeight = configuration.screenHeightDp.dp
            val desiredHeight = screenHeight / 2

            // multiply the height of a single line of text by the number of strings in the list
            // to get the total height of the LazyColumn
            // if the total height of the LazyColumn is greater than half the screen height, the
            // height of the LazyColumn is set to half the screen height
            // otherwise the full LazyColumn is displayed
            val columnHeight =
                if (textLayoutResult.size.height.dp * stringList.size > desiredHeight) {
                    desiredHeight
                } else {
                    (textLayoutResult.size.height.dp * stringList.size)
                }

            // Create a box of height columnHeight to hold the LazyColumn
            Box(
                modifier = Modifier.height(columnHeight)
            ) {
                // The LazyColum: each row contains one string from the list and an IconButton
                LazyColumn(
                    modifier = Modifier
                        .fillMaxWidth()
                ) {
                    items(stringList) { str ->
                        Row(
                            verticalAlignment = Alignment.CenterVertically,
                            horizontalArrangement = Arrangement.SpaceBetween,
                            modifier = Modifier.fillMaxWidth()
                        ) {
                            Text(
                                text = str,
                            )
                            IconButton(
                                onClick = { }
                            ) {
                                Icon(
                                    imageVector = Icons.Filled.CheckCircle,
                                    contentDescription = "icon button"
                                )
                            }
                        }
                    }
                }
            }
        }

        // some text composables after the LazyColumn
        Text("Text after LazyColumn")
        Text("More text after LazyColumn")
    }
}

My questions are:

  1. How do I remove the extra space between the initial Row composable and the LazyColumn?
  2. How do I correctly measure the height of the LazyColumn so that rows aren't cut off when the LazyColumn takes up less than half of the screen. Or in other words how to I get the height of a row?

(Or if there's a better way to do this, please let me know!)

Upvotes: 0

Views: 24

Answers (0)

Related Questions