Reputation: 385
I want to create the following layout in Jetpack compose.
I've tried creating two lists inside a vertical scrollable Box but that's not possible as I got the this error: "java.lang.IllegalStateException: Nesting scrollable in the same direction layouts like ScrollableContainer and LazyColumn 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()."
I've tried creating two different lists inside a parent list by using the following code, but that doesn't work either.
@Composable
fun MainList() {
LazyColumn() {
item {
/* LazyRow code here */
}
item {
/* LazyColumn code here */
}
}
}
Now I'm clueless about what else could I try to achieve two lists (one vertical and one horizontal) on the same activity and keep the activity vertically scrollable too.
Upvotes: 34
Views: 17860
Reputation: 341
An alternative equivalent of nested RecyclerViews is nested LazyColumns, where the heights of the inner LazyColumns are specified or constant, and the inner LazyColumns are placed inside item {} blocks.
Unlike the accepted answer, this approach relies on the .height() modifier to avoid the "java.lang.IllegalStateException: Nesting scrollable in the same direction layouts like ScrollableContainer and LazyColumn is not allowed... " error. Also, this approach addresses the scenario of nested scrolling in the same direction.
Here is an example code and output.
@Composable
fun NestedLists() {
LazyColumn(Modifier.fillMaxSize().padding(12.dp),
horizontalAlignment = Alignment.CenterHorizontally) {
//Header for first inner list
item {
Text(text = "List of numbers:", style = MaterialTheme.typography.h5)
}
// First, scrollable, inner list
item {
// Note the important height modifier.
LazyColumn(Modifier.height(100.dp)){
val numbersList = (0 .. 400 step 4).toList()
itemsIndexed(numbersList) { index, multipleOf4 ->
Text(text = "$multipleOf4", style = TextStyle(fontSize = 22.sp, color = Color.Blue))
}
}
}
// Header for second inner list
item {
Text(text = "List of letters:", style = MaterialTheme.typography.h5)
}
// Second, scrollable, inner list
item {
// Note the important height modifier.
LazyColumn(Modifier.height(200.dp)) {
val lettersList = ('a' .. 'z').toList()
itemsIndexed(lettersList) { index, letter ->
Text(text = "$letter", style = TextStyle(color = Color.Blue, fontSize = 22.sp))
}
}
}
}
}
Upvotes: 4
Reputation: 23964
I think the best option, would be if the LazyVerticalGrid
allows some sort of expand logic on each item, but looks like it's not supported yet (beta-03).
So I'm leaving here my solution using one single LazyColumn
for the entire list and LazyRow
for "My Books" section.
LazyColumn(
modifier = Modifier.fillMaxSize(),
) {
// My Books section
item {
Column(modifier = Modifier.fillMaxWidth()) {
Text("My Books")
LazyRow {
items(books) { item ->
// Each Item
}
}
}
}
// Whishlisted Books title
item {
Text("Whishlisted Books", style = MaterialTheme.typography.h4)
}
// Turning the list in a list of lists of two elements each
items(wishlisted.windowed(2, 2, true)) { item ->
Row {
// Draw item[0]
// Draw item[1]
}
}
}
Here is my gist with the full solution and the result is listed below.
Upvotes: 46
Reputation: 364441
You can do something like:
Column(Modifier.fillMaxWidth()) {
LazyRow() {
items(itemsList){
//.....
}
}
LazyColumn() {
items(itemsList2){
//..
}
}
}
or:
Column(Modifier.fillMaxWidth()) {
LazyRow() {
items(itemsList){
//....
}
}
LazyVerticalGrid(cells = GridCells.Fixed(2)) {
items(itemsList2.size){
//....
}
}
}
Upvotes: 3