I am trying to create a LazyColumn
with a sticky header and a sticky sub-header.
The functionality I would like to achieve what is demonstrated in this GIF.
My source code is as follows:
The data item which will be used
class Item(
val type: String, // Will be used as header
val subType: String, // Will be used as sub-header
val title: String,
val description: String,
val imageUrl: String)
An example of the item usage
Item("Movie", "Action",
"Shang-Chi and the Legend of the Ten Rings",
"Shang-Chi, the master of unarmed weaponry-based Kung Fu, is forced to " +
"confront his past after being drawn into the Ten Rings organization.",
"https://threepixelslab.gr/wp-content/uploads/2021/04/Shang-Chi-and-the-Legend-of-the-Ten-Rings.jpg")
The list composing
@Composable
fun MainList(data: List<Item>) {
val mainGroup = data.groupBy { it.type }
LazyColumn {
mainGroup.forEach { (type, groupedData) ->
val subGroup = groupedData.groupBy { it.subType }
stickyHeader {
Header(text = type)
}
item {
LazyColumn {
subGroup.forEach { (subType, subGroupedData) ->
stickyHeader { Header(text = subType) }
items(subGroupedData) {
SimpleItem(item = it)
}
}
}
}
}
}
}
The error
java.lang.IllegalStateException: Nesting scrollable in the same direction layouts like LazyColumn and Column(Modifier.verticalScroll()) is not allowed. If you want to add a header before the list of items please take a look on LazyColumn component which has a DSL api which allows to first add a header via item() function and then the list of items via items().
at androidx.compose.foundation.ScrollKt.assertNotNestingScrollableContainers-K40F9xA(Scroll.kt:370) at androidx.compose.foundation.lazy.LazyListKt$LazyList$1.invoke-0kLqBqw(LazyList.kt:96) at androidx.compose.foundation.lazy.LazyListKt$LazyList$1.invoke(LazyList.kt:95) at androidx.compose.ui.layout.SubcomposeLayoutState$createMeasurePolicy$1.measure-3p2s80s(SubcomposeLayout.kt:345) at androidx.compose.ui.node.InnerPlaceable.measure-BRTryo0(InnerPlaceable.kt:43) at androidx.compose.foundation.layout.PaddingValuesModifier.measure-3p2s80s(Padding.kt:417) at androidx.compose.ui.node.ModifiedLayoutNode.measure-BRTryo0(ModifiedLayoutNode.kt:39) at androidx.compose.ui.graphics.SimpleGraphicsLayerModifier.measure-3p2s80s(GraphicsLayerModifier.kt:219) at androidx.compose.ui.node.ModifiedLayoutNode.measure-BRTryo0(ModifiedLayoutNode.kt:39) at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.measure-BRTryo0(DelegatingLayoutNodeWrapper.kt:116) at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.measure-BRTryo0(DelegatingLayoutNodeWrapper.kt:116) at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.measure-BRTryo0(DelegatingLayoutNodeWrapper.kt:116) at androidx.compose.ui.node.OuterMeasurablePlaceable$remeasure$3.invoke(OuterMeasurablePlaceable.kt:100) at androidx.compose.ui.node.OuterMeasurablePlaceable$remeasure$3.invoke(OuterMeasurablePlaceable.kt:99) at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:128) at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:75) at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.kt:63) at androidx.compose.ui.node.OuterMeasurablePlaceable.remeasure-BRTryo0(OuterMeasurablePlaceable.kt:99) at androidx.compose.ui.node.OuterMeasurablePlaceable.measure-BRTryo0(OuterMeasurablePlaceable.kt:71) at androidx.compose.ui.node.LayoutNode.measure-BRTryo0(LayoutNode.kt:1227) at androidx.compose.foundation.layout.RowColumnImplKt$rowColumnMeasurePolicy$1.measure-3p2s80s(RowColumnImpl.kt:89) at androidx.compose.ui.node.InnerPlaceable.measure-BRTryo0(InnerPlaceable.kt:43) at androidx.compose.ui.node.OuterMeasurablePlaceable$remeasure$3.invoke(OuterMeasurablePlaceable.kt:100) at androidx.compose.ui.node.OuterMeasurablePlaceable$remeasure$3.invoke(OuterMeasurablePlaceable.kt:99) at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:128) at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:75) at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.kt:63) at androidx.compose.ui.node.OuterMeasurablePlaceable.remeasure-BRTryo0(OuterMeasurablePlaceable.kt:99) at androidx.compose.ui.node.OuterMeasurablePlaceable.measure-BRTryo0(OuterMeasurablePlaceable.kt:71) at androidx.compose.ui.node.LayoutNode.measure-BRTryo0(LayoutNode.kt:1227) at androidx.compose.foundation.lazy.LazyMeasuredItemProvider.getAndMeasure-ZjPyQlc(LazyMeasuredItemProvider.kt:50) at androidx.compose.foundation.lazy.LazyListMeasureKt.measureLazyList-9CW8viI(LazyListMeasure.kt:145) at androidx.compose.foundation.lazy.LazyListKt$LazyList$1.invoke-0kLqBqw(LazyList.kt:152) at androidx.compose.foundation.lazy.LazyListKt$LazyList$1.invoke(LazyList.kt:95) at androidx.compose.ui.layout.SubcomposeLayoutState$createMeasurePolicy$1.measure-3p2s80s(SubcomposeLayout.kt:345)
Is it possible to implement this kind of list in Compose?