As far as I can see it's currently not possible to...
# compose
f
As far as I can see it's currently not possible to have LazyColumn containing another LazyColumn. Is there a known way to get the following behavior in compose: • Vertical list of lazy loaded "modules" (supports paging) • Module is either horizontal or vertical (also lazy loading) I can currently make a lazy vertical list of modules if all of the modules are horizontal, but not if they are vertical. Using RecyclerView I can do this if I accept that the vertical modules will bind all items when bound. Would love some input on this! 🙂
n
what do you mean by
Using RecyclerView I can do this if I accept that the vertical modules will bind all items when bound.
? that with a recyclerview a vertical module won' be lazy ?
f
The nested vertical recycler view will bind all its children at once as the viewport is infinite.
Assuming you're using LinearLayoutManager
n
so basically, for vertical module with compose, you can achieve the same behavior with a Column and a forEach in it for having inner LazyColumn, I wonder if Compose can tackle the issue or not...
f
Unfortunately, I get the same issue with Column with verticalScroll. I get a runtime exception.
n
I think you should not have vertical scroll then, just take the content size, but I assume that is not the behavior you had with the RecyclerView right ?
f
Thanks for sparring. I'm not sure what exactly you mean with "not have vertical scroll"? One challenge is that the content size is unknown 🙂 It's paginated list of modules. I could try to iterate over it upon content refresh, but I'd end up with some sort of nested vertical scroll. E.g. Column with modules, then one module type with LazyColumn. This solution needs to be generic. I don't know in advance the number of modules, nor the type of module (horisontal/vertical), nor the module item count.
n
oh ok I think I see the issue
my original thinking was something like
Copy code
LazyColumn {
   items(modules) {
    module ->
    if(module is VerticalModule) {
      VerticalModuleContent(module)
    }
   }
}

VerticalModuleContent(module) {
   Column {
   module.items.forEach {
     Item()... 
   }
  }
}
f
Thanks for the input. The challenge here is that the vertical module could contain hundreds, or even thousands of items, each with an image that needs to be loaded etc. So it has to be lazy. It would also be a requirement to get pagination working as far as I can see.
n
ok, well that's an interesting use case
j
You have to put everything inside one LazyColumn... I think something like this should work:
Copy code
val items1: LazyPagingItems<T>
val items2: LazyPagingItems<T>
val items3: LazyPagingItems<T>

LazyColumn {
  items(count = items1.itemCount) { index ->
    itemContent(items1[index])
  }

  if (items1.loadState.append is LoadState.NotLoading && items1.loadState.append.endOfPaginationReached) {
    items(count = items2.itemCount) { index ->
      itemContent(items2[index])
    }

    if (items2.loadState ...) {
      ...
    }
  }
}
f
Thanks for the inputs. I’ll need to dig into this. Here
items1
 etc would also be a list of unknown size.
One challenge/issue is that the content padding is also added to each nested item in the vertical list. Where it should only be added per “module”. I suppose I can get around this though.
a
to convert that style of solution into the highly generic pluggable framework you want, I'd suggest phrasing your vertical module as a
LazyListScope.() -> Unit
lambda that automatically calls
item/items
per each subelement of the module
if you want perfect symmetry of API with the horizontal modules, you could have the horizontal ones just add exactly one
item { LazyRow ... }
f
@Alexandre Elias [G] Thanks for the input. This is exactly what I’ve done so far. Still need to experiment with paging, but it’s looking promising. Very exciting times.