Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for sticky headers #164

Closed
elihart opened this issue Mar 22, 2017 · 30 comments
Closed

Support for sticky headers #164

elihart opened this issue Mar 22, 2017 · 30 comments

Comments

@elihart
Copy link
Contributor

elihart commented Mar 22, 2017

We are working on this, and hope to release support in a 2.x release.

There are two ways to support this.

  1. An item decoration to copy the view of a model. This is simpler, but you lose touch functionality. This would be what we initially support.
  2. Using a custom layout manager to create a fully functional duplicate view. There are some libraries that use this approach, but I am hesitant to pursue it because layout managers are very complex and using Linear/GridLayoutManager is the safest/optimized approach. I have an idea on how we might extend LinearLayoutManager though, which I can hopefully work on over the next few months.

If anyone is interested in helping with these, please let me know!

@VisheshVadhera
Copy link

Hey @elihart, we just chatted over on reddit.

I think the second approach definitely sounds interesting and can be a good starting point. Can you please elaborate a bit more on the second approach?

@elihart
Copy link
Contributor Author

elihart commented Apr 11, 2017

Hi! Sure thing. I'm basically thinking that a custom layout manager can create the view that we want to sticky, and keep it positioned at the top of the screen. It would scroll away as another sticky view pushed it off screen.

There are similar approaches out there. https://github.com/TonicArtos/SuperSLiM seems like the best one. The problems I have with this are:

  1. It's not immediately usable by epoxy since we have our own models to interface with. This means we would have to fork it and manage it
  2. It's completely custom so we lose all of the default behavior of the LinearLayoutManager.

I think the Android team has done a great job with the default layout managers. Those classes are very complicated and handle a ton of situations for us. I really don't want a custom layout manager because I think it would be worse and harder to maintain.

So, ideally we can make a layout manager that extends LinearLayoutManager, and just adds a little bit of functionality to figure out which view should be stuck to the top and keep it there. As far as I can tell so far we could need a custom view to do this - right now I am thinking a framelayout with a nested RecyclerView. Our layoutmanager would get the sticky view from the recyclerview and add it to the framelayout. It can't add it to the recyclerview because that would mess with the LinearLayoutManager internals which expects the child views to be a certain way.

Then our layoutmanager would simply translate the header as needed to scroll it off and replace it with the next header. An interface on a model would indicate that it wants to make its view sticky.

I played around with this idea for a day and it seems possible. You can see my (very rough) code at https://github.com/airbnb/epoxy/compare/eli/sticky

I think this approach can work fairly nice. Attaching the view to a framelayout is a bit hacky, but as far as I can tell it will work.

I also just pushed our WIP code for sticky headers via item decorations https://github.com/airbnb/epoxy/compare/eli-sticky_header_decoration.

My coworker started that and then hasn't had time to finish. I think the item decoration approach is nice if you just need a basic view. however, you lose all view interactivity. The only way to keep that is with the layout manager approach. So I think it would be great to have both options for people depending on what they need, so they can use the decorations if they like and avoid the need for a custom recyclerview.

The decoration code is mostly working, but is unpolished and needs optimization and testing. Feel free to contribute to that too if you like, but I agree that the layout manager work is more interesting and more open ended. You may like to look at the item decoration code though to get logic on how it positions the headers. The code was modified from https://github.com/timehop/sticky-headers-recyclerview

If anyone else wants to work on that instead ^ please go for it.

I think the layout manager task is a great way to start contributing since you don't need much knowledge of Epoxy. It would be great if you also want to work on annotation processing, but that code is pretty confusing and would take quite a bit of time to ramp up on. if you are interested though, I have these two tasks that are up for grabs:
#187
#186

That was a bit of a ramble, and a pretty rough outline of what I have in mind. It's very open ended, so hopefully you're up for it :) I would love to work on this, but I don't have time, it should be cool though. let me know your thoughts!

@tschuchortdev
Copy link

@elihart Do you think something like a Decorator class would be possible to be able to use your own layoutmanager instead of just the ones that epoxy provides?

@VisheshVadhera
Copy link

Fantastic! Thanks! That should get me started.

So I'll start off the work tomorrow morning and would definitely be using the libraries and code samples which you have shared as a reference. If I get something interesting in my mind, I'll post here. Stuff looks great!

I'll checkout the other two issues as well once I am done with this one.

@elihart
Copy link
Contributor Author

elihart commented Apr 12, 2017

@tschuchortdev With the decorator approach it should work fine to use whatever layout manager you want with it. That's one advantage of that approach.

@tschuchortdev
Copy link

@elihart: I meant the decorator pattern not android ItemDecorators in case that was unclear. I.e. a class that forwards calls to any LayoutManager of your choice at run time, thus extending it without actually subclassing. But I don't know if it's actually possible (or sensible) with the myriad of different LayoutManagers there are.

@elihart
Copy link
Contributor Author

elihart commented Apr 12, 2017

@tschuchortdev ah sorry. My initial thought was that would be kind of crazy since layout managers are so complicated and could have very different implementations, however I guess it could be possible and is a nice idea that is worth exploring.

It's been a little while since I worked on this so I'm a bit rusty on the layout manager usage. I think if we can do it by using only methods on the base LayoutManager class and not using any functionality from LinearLayoutManager then it could be possible.

@elihart
Copy link
Contributor Author

elihart commented Apr 12, 2017

@VisheshVadhera Awesome! Hope you have good luck with it, keep us posted :)

@VisheshVadhera
Copy link

VisheshVadhera commented Apr 14, 2017

Adding https://github.com/ShamylZakariya/StickyHeaders as a reference.

@elihart
Copy link
Contributor Author

elihart commented Apr 14, 2017

@VisheshVadhera good find! how's the work coming so far?

@VisheshVadhera
Copy link

VisheshVadhera commented Apr 14, 2017

It's coming along well. Spent last couple of days just understanding LayoutManager's internals. This series was certainly helpful.

I am right now also exploring the option of having our own custom LayoutManager extending RecyclerView.LayoutManager and using that to achieve stickyness. Though as you said that is going to be extremely complex and harder to maintain. What is your take on this? Do you think I should be spending time at all on this approach?

The approach which you suggested (using a frameLayout) definitely sounds interesting and I think I will be fiddling around with your starter code over the weekend.

One thing which I wanted to ask. Do we want sticky headers only for vertical recycler views or we are thinking of having this functionality for horizontal recycler views as well?

@VisheshVadhera
Copy link

Hey, been busy with some other stuff. I'll take a crack at this one over the weekend. Meanwhile if someone else wants to work in this one, feel free to start.

@elihart
Copy link
Contributor Author

elihart commented Apr 21, 2017

@VisheshVadhera Good luck! Glad you are getting some understanding of layout managers, they definitely are tricky and it's something I don't understand as well as I'd like.

I am right now also exploring the option of having our own custom LayoutManager extending RecyclerView.LayoutManager and using that to achieve stickyness. Though as you said that is going to be extremely complex and harder to maintain. What is your take on this? Do you think I should be spending time at all on this approach?

If you copy a great sticky header layout manager from another library (assuming the license allows it) and simply make a few changes to make it work with Epoxy model's, then that's better than nothing and worth a first version at least. I would worry that things like animations, accessibility, optimization, etc would suffer though, and I'd prefer not to maintain that.

Do we want sticky headers only for vertical recycler views or we are thinking of having this functionality for horizontal recycler views as well?

Ideally we would have it for both, and also for GridLayoutManager. That doesn't have to happen all at once though. I think if you can get vertical stickiness working by extending the LinearLayoutManager, then supporting horizontal would be trivial. I would also think that we could then reuse that code with GridLayoutManager fairly easily.

Good luck trying it out! My code was very basic and just did enough to get a duplicate view added to the external FrameLayout as proof that it could work.

And sorry for the late response, I meant to reply a week ago :(

@davideas
Copy link

davideas commented May 10, 2017

@elihart, I've already developed, since long time already, the technique with the FrameLayout in my FlexibleAdapter project. It works very well now (after many bug fixes occurred during time). Of course it's something custom for the models I invented and I had to adapt the ViewHolder as well. The core class is called StickyHeaderHelper, if you want you can check it out.

I suggest to not go through ItemDecoration, very soon you want to add the touch support, and some kind of elaborations, for instance, when you want to update the content while sticky, etc...

The best solutions is indeed a custom LayoutManager and indeed I agree with you that it is very complex to implement. Are you going on this solution or on FrameLayout?

@elihart
Copy link
Contributor Author

elihart commented May 10, 2017

@davideas Thanks for posting! I hadn't seen your FlexibleAdapter project before so I'm glad you shared. I'll check it out right now. Seems like I've done very similar things in Epoxy, but relied more on annotation processing to generate code. You have a lot of great things in there though!

Thanks for the suggestions - I'm not sure if we'll go with the framelayout or custom layout manager approach yet. I haven't had time to work on this in a while, but hopefully we can get to it some time.

@littleGnAl
Copy link

littleGnAl commented Jul 18, 2017

Hi @elihart , any progress of this? I tried https://github.com/airbnb/epoxy/compare/eli-sticky_header_decoration. and I found the StickyModelDecoration#getHeaderModelForPosition(int position) for the position 0 would always return null , and it does not support reverseLayout such like new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, true).

@elihart
Copy link
Contributor Author

elihart commented Jul 18, 2017

@littleGnAl that branch is very old and incomplete. Vishesh started to take over the work but seems to have dropped it a while ago.

We haven't needed this, so I haven't done it myself and haven't made progress. If somebody wants to take it on that would be great

@beatbrot
Copy link

@elihart Would it be possible to give us a little heads-up on the current state of sticky list headers? Was any work done on it in the past? :)

@mhdatie
Copy link

mhdatie commented Apr 19, 2018

Same as @beatbrot. We started adopting Epoxy at my workplace and would like to know the status of this. Thanks!

@elihart
Copy link
Contributor Author

elihart commented Apr 21, 2018

Unfortunately there hasn't been any work on this outside of the old comments you see above. I am also not planning to work on this at the moment.

I agree it would be great to have, but we haven't needed it in our app so I haven't prioritized it.

I would be happy to help review a PR if somebody wants to contribute. Now that we have the EpoxyRecyclerView we could possibly leverage that.

@elihart
Copy link
Contributor Author

elihart commented Apr 21, 2018

My thinking currently about this is that going with the item decoration approach like https://github.com/timehop/sticky-headers-recyclerview would be an easy way to provide basic sticky support and I think it could be done as an add on module instead of modifying the core Epoxy controller/adapter, which I'd like to avoid. I don't think it would be too hard to adapt that library to work with epoxy. I think the main disadvantage is that views lose their interactive functionality

Going the custom layout manager path provides more power, but it has a lot of complexity and things needs to be tightly entangled which I am cautious about.

@egek92
Copy link

egek92 commented May 3, 2018

Any update on this?

@elihart
Copy link
Contributor Author

elihart commented May 4, 2018

No, this thread will be updated if anything changes.

@lucamtudor
Copy link

I would love to see some progress on this 😁. (also, thanks for this great lib!)

@jonasbark
Copy link

Here's an example implementation which is based on https://gist.github.com/saber-solooki/edeb57be63d2a60ef551676067c66c71 but adjusted to work well with Epoxy:

https://gist.github.com/jonasbark/f1e1373705cfe8f6a7036763f7326f7c

You can give any Item ID to the item decoration and the decoration will fix its view on top of the RecyclerView. Please note it isn't perfectly implemented nor optimized for performance but it works well as a proof of concept.

@elihart
Copy link
Contributor Author

elihart commented Feb 7, 2019

Thanks for sharing @jonasbark, I think an item decoration approach is fine for some use cases as long as people are aware of the limitations (eg not being able to duplicate input handling)

@AkshayChordiya
Copy link
Contributor

@elihart @jonasbark The implementation of sticky header with item decoration works pretty well.

Like @elihart suggested before. The disadvantage is that views lose their interactive functionality.
Is there a way to still keep interactive functionality or manually duplicate it?

@AkshayChordiya
Copy link
Contributor

AkshayChordiya commented Oct 9, 2019

@elihart I recently made the LayoutManager by extending the LinearLayoutManager to show sticky header. I'm happy to contribute and will create a PR soon.

@dleonett
Copy link

dleonett commented Jan 2, 2020

Hello guys, any thoughts on @AkshayChordiya PR? I'm very interested in this feature. Hope it gets merged soon. Thank you all!

@AkshayChordiya
Copy link
Contributor

@elihart We can close this issue now 🎉

@elihart elihart closed this as completed May 8, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests