airbnb / epoxy

Epoxy is an Android library for building complex screens in a RecyclerView
https://goo.gl/eIK82p
Apache License 2.0
8.5k stars 733 forks source link

Views overlaying Carousel #685

Closed lawrencebautista closed 5 years ago

lawrencebautista commented 5 years ago

Hi, thanks for the Carousel class, it's been really useful.

My problem is that I'd like to add a numerical page indicator view overlaying the Carousel.

It should be anchored to the top right of the carousel, and I think it would be too complicated to do with an ItemDecorator (unlike the dots indicator as mentioned https://github.com/airbnb/epoxy/issues/602) so I would like to just use a TextView.

Is this possible to do with Carousel? I can't find a way since it extends RecyclerView directly and therefore I can't wrap it in a FrameLayout or something so I can add the TextView

elihart commented 5 years ago

You can create a custom Epoxy model (either custom view or viewholder) that wraps the carousel view in whatever other view you want, and overlay the indicator that way.

The sample app shows a model group that has a nested carousel like this

lawrencebautista commented 5 years ago

It's a bit unclear to me how to wrap the carousel view. Here's my attempt but it's wrong:

@EpoxyModelClass(layout = R.layout.carousel_with_indicator) // layout file contains a Carousel view??
abstract class PageIndicatorCarouselModel : EpoxyModelWithHolder<PageIndicatorCarouselModel.Holder>() {

    @EpoxyAttribute
    val models: List<EpoxyModel<Any>> = emptyList()

    override fun bind(holder: Holder) {
        holder.carousel?.setModels(models)
        // ... logic to hook pageIndicator to carousel
    }

    class Holder: EpoxyHolder() {
        var carousel: Carousel? = null
        var pageIndicator: TextView? = null

        override fun bindView(itemView: View) {
            carousel = itemView.findViewById(R.id.carousel)
            pageIndicator = itemView.findViewById(R.id.pageIndicator)
        }
    }
}

I need to somehow use CarouselModel_ instead of Carousel right? but the layout does not have an EpoxyController to add it to.

Also looked at the sample app, which uses an EpoxyModelGroup. Looks like it could work, but on your docs you say

This is NOT a replacement for creating a custom view. Models in a group should be independent and not rely on each other's state.

Clearly the page indicator relies on the state of the Carousel, so is that the right approach here?

elihart commented 5 years ago

you don't need to use CarouselModel_ just use the normal Carousel view and embed it in your custom view.

you're just building a custom view, nothing special about that. you'll have to connect all the data yourself and not reuse CarouselModel_

elihart commented 5 years ago

I think EpoxyModelGroup could actually work for you here to simplify and reuse CarouselModel_ - the recommendation against being dependent on state still stands, but in this case you're not really dependent, the carousel can emit a scroll event listener and stay separated besides that

lawrencebautista commented 5 years ago

Thanks, I went with the EpoxyModelGroup approach