6

In one of my composables, a Lazycolumn is nested inside a Column composable. I want to be able to scroll the entire Column along with the Lazycolumn. But, specifying the verticalScroll modifier property on Column results in the following exception causing the app to crash. How can I fix this?

Exception

java.lang.IllegalStateException: Vertically scrollable component was measured with an infinity maximum height constraints, which is disallowed. One of the common reasons is nesting layouts like LazyColumn and Column(Modifier.verticalScroll()).

Composable

Column(
    modifier = Modifier
        .fillMaxWidth()
        .verticalScroll(rememberScrollState())
        .padding(bottom = 100.dp),
    verticalArrangement = Arrangement.Center,
    horizontalAlignment = Alignment.CenterHorizontally
) {
    LazyColumn(
        modifier = Modifier
            .fillMaxWidth()
    ) {
        items(
            items = allItems!!,
            key = { item ->
                item.id
            }
        ) { item ->
            ShoppingListScreenItem(
                navController = navController,
                item = item,
                sharedViewModel = sharedViewModel
            ) { isChecked ->
                scope.launch {
                    shoppingListScreenViewModel.changeItemChecked(item!!, isChecked)
                }
            }
        }
    }

   ...

Button(
    modifier = Modifier.padding(vertical = 24.dp),
    onClick = {
        navController.navigate(NavScreens.AddItemScreen.route) {
            popUpTo(NavScreens.AddItemScreen.route) {
                inclusive = true
            }
        }
    }
) {
    Text("Go to add item screen")
  }
}

2 Answers 2

6

This happens when you wish to measure your LazyColumn with Constraints with Constraints.Infinity for the maxHeight which is not permitted as described in error log. There should be a fixed height or you shouldn't have another Scrollable with same orientation.

Column(
    modifier = Modifier
         // This is the cause
        .verticalScroll(rememberScrollState())
) {
    LazyColumn(
       // and not having a Modifier that could return non-infinite max height contraint
        modifier = Modifier
            .fillMaxWidth()
    ) {

}

If you don't know exact height you can assign Modifier.weight(1f) to LazyColumn.

Contraints

This section is extra about `Constraints` and measurement you can skip this part if you are not interested in how it works.

What i mean by measuring with with Constraints.Infinity is when you create a Layout in Compose you use

Layout(modifier=modifier, content=content){
     measurables: List<Measurable>, constraints: Constraints ->
}

You get child Composables as List<Measurable> which you can measure with Constraints provided by parent or the one you see fit by updating existing one with Constraints.copy or fixed one when you build a custom Composable with Layout.

val placeable = measurable.measure(constraints)

Constraints min/max width/height changes based on size modifier or scroll. When there is a scroll and you don't use any size modifier, Constraints return minHeight =0, maxHeight= Int.MAX_VALUE as Constraints.Infinity

Modifier.fillMaxWidth()

enter image description here

Modifier.fillMaxWidth().weight(1f)

enter image description here

Easiest way to check Constraints with different Modifiers or with scroll is getting it from BoxWithConstraints

Sign up to request clarification or add additional context in comments.

4 Comments

I just set the height on the LazyColumn and there's no exception thrown, but setting a height greater than the total number of items in the LazyColumn causes the screen to pull back when flick scrolling. How can I fix that?
Placing Modifier.weight(1f) on the LazyColumn causes the Lazy list to completely disappear on the screen.
I made an example with simple items using Modifier.weight(1f), image above is from that it worked fine setting same height to LazyColumn. Comment your LazyColumn and put a BoxWithConstraints to check the max height you get. But you might not need Column in the first place. You might achieve what you wish with only LazyColumn with a structure for instance item{Header()} items({your items} and item{Footer()}. And it's strange issue with pull back i don't know why it occurs especially without testing layout.
You might check this video about it youtu.be/1ANt65eoNhQ?t=898
2

You should use nested scrolling

This is the google dev document: https://developer.android.com/develop/ui/compose/touch-input/pointer-input/scroll

verticalScroll only works with nested scrolling in different directions. just like:

Column(
    modifier = Modifier
        .verticalScroll(rememberScrollState())
) {
    LazyRow(
        modifier = Modifier
            .fillMaxWidth()
    ) {

}

Row(
    modifier = Modifier
        .horizontalScroll(rememberScrollState())
) {
    LazyColumn(
        modifier = Modifier
            .fillMaxHeight()
    ) {}

}

So if you want to use column nested lazyColumn you have to use NestedScroll.

val nested = object : NestedScrollConnection {
    override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity {
        return super.onPostFling(consumed, available)
    }
    override fun onPostScroll(
        consumed: Offset,
        available: Offset,
        source: NestedScrollSource
    ): Offset {
        return super.onPostScroll(consumed, available, source)
    }
    override suspend fun onPreFling(available: Velocity): Velocity {
        return super.onPreFling(available)
    }
    override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
        return super.onPreScroll(available, source)
    }
}
Column(
    modifier = Modifier.nestedScroll(nested)
) {
    SideEffect {
        Log.i("refresh", "Column")
    }
    
    LazyColumn {
        
    }
    LazyColumn(
        modifier = Modifier
    ) {
        
    }
}

This is just an example. Please refer to the google dev documentation for specific requirements.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.