Epoxy: How to use `PagingEpoxyController` with a header?

Created on 26 Sep 2018  路  6Comments  路  Source: airbnb/epoxy

What I'd like to do: Display a list of items (this is a PagedList, because I use the paging lib to request data as I scroll) but also have a header at the top.

With a normal TypedEpoxyController, I can achieve this by having some state type that contains the header and the list, and I set it using TypedEpoxyController.setData().

However, inside the PagingEpoxyController, all I have the option for is submitList(pagedList) or submitList(itemList) and I'm not sure how to approach including a header in all of this. Any nudges in the right direction could help.

If I'm able to get this working, I'm more than happy to contribute back with a PR including samples of doing this.

Most helpful comment

I've just published 2.18.0 release, which includes a new, improve paged list support (created by Yigit from the Android team). Check out the wiki that I just updated too: https://github.com/airbnb/epoxy/wiki/Paging-Support

TLDR: extend PagedListEpoxyController to create your controller. override buildItemModel to define how each item in the paged list gets converted to an epoxy model. then override addModels to modify the items list to add headers or whatever other changes you want.

Edit: It seems like part of your confusion is a TypedEpoxyController vs a base EpoxyController. With the typed controller you specific all of your data via setData as a helper. In a basic controller, like the paging controller you have to set it manually. This could be anything you want, like a constructor param, or a simple field. Just call requestModelBuild if it ever changes. This doesn't have to do with paging so much, its the same as a normal epoxy controller

All 6 comments

I've just published 2.18.0 release, which includes a new, improve paged list support (created by Yigit from the Android team). Check out the wiki that I just updated too: https://github.com/airbnb/epoxy/wiki/Paging-Support

TLDR: extend PagedListEpoxyController to create your controller. override buildItemModel to define how each item in the paged list gets converted to an epoxy model. then override addModels to modify the items list to add headers or whatever other changes you want.

Edit: It seems like part of your confusion is a TypedEpoxyController vs a base EpoxyController. With the typed controller you specific all of your data via setData as a helper. In a basic controller, like the paging controller you have to set it manually. This could be anything you want, like a constructor param, or a simple field. Just call requestModelBuild if it ever changes. This doesn't have to do with paging so much, its the same as a normal epoxy controller

This seems really helpful! Will upgrade and give it a shot. Thanks so much.

Thanks so much @elihart . Looking back over the sample that did exactly what I wanted - a paged list but with a fixed header at the top. I just didn't realize that's what was happening (should have ran the sample).

I really appreciate the quick turn around on this. Closing the ticket - but if I run into any other problems I'll reopen or contribute suggestions. :)

What if I need not one but few headers ( for example - date header for the group of messages in chat). How I can achieve this with addModels?

What if I need not one but few headers ( for example - date header for the group of messages in chat). How I can achieve this with addModels?

Seems like something like that should work:

override fun addModels(models: List<EpoxyModel<*>>) {
        if (models.size == 3000) {
            pagingView {
                id("1 header")
                name("showing ${models.size} items")
            }
            super.addModels(models.subList(0, 1000))

            pagingView {
                id("2 header")
                name("showing ${models.size} items")
            }
            super.addModels(models.subList(1000, 2000))

            pagingView {
                id("3 header")
                name("showing ${models.size} items")
            }
            super.addModels(models.subList(2000, 3000))
        }
    }

Depending on your use case, you could make your header something you conditionally show on the model. For example, we use Epoxy on a message thread page, and we want to show a timestamp in certain groups, but that timestamp UI is actually built into the message model, and in buildItemModel we handle the conditional logic for whether or not it should be shown. So this way addModels() is still pretty clean.

Depending on what kind of header you mean here it might not be that simple. But you could also consider an interceptor, perhaps? I'm not :100: if the interceptors let you add new items or not.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

qbait picture qbait  路  3Comments

Sergiyss picture Sergiyss  路  6Comments

aliab picture aliab  路  3Comments

ailuoyi picture ailuoyi  路  5Comments

jamesarich picture jamesarich  路  5Comments