This fork is based on the code from timehop. Although, instead of sticky headers, this implementation is a replica of the native Android contacts app, which has the letters of each alphabetical section on the left hand side as you scroll.
Example of the forked code running:
Currently this is not hosted anywhere, except right here. If there is any interest, I'd be happy to get it hosted somewhere to be able to be installed much easier.
For now, the process I am using is...
- Open the project in Android studio
- Create the
jar
(see screenshots below for more info): - Import/add the jar into your own Android Studio project. See this Stack Overflow question on how to do this.
Original README below
This decorator allows you to easily create section headers for RecyclerViews using a LinearLayoutManager in either vertical or horizontal orientation.
Credit to Emil Sjölander for creating StickyListHeaders, a library that many of us relied on for sticky headers in our listviews.
Here is a quick video of it in action (click to see the full video):
(Took these out because this is not how it looks anymore)
There are three main classes, StickyRecyclerHeadersAdapter
, StickyRecyclerHeadersDecoration
,
and StickyRecyclerHeadersTouchListener
.
StickyRecyclerHeadersAdapter
has a very similar interface to the RecyclerView.Adapter
, and it
is recommended that you make your RecyclerView.Adapter
implement StickyRecyclerHeadersAdapter
.
There interface looks like this:
public interface StickyRecyclerHeadersAdapter<VH extends RecyclerView.ViewHolder> {
public long getHeaderId(int position);
public VH onCreateHeaderViewHolder(ViewGroup parent);
public void onBindHeaderViewHolder(VH holder, int position);
public int getItemCount();
}
The second class, StickyRecyclerHeadersDecoration
, is where most of the magic happens, and does
not require any configuration on your end. Here's an example from onCreate()
in an activity:
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);
mAdapter = new MyStickyRecyclerHeadersAdapter();
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setLayoutManager(new LinearLayoutManager(context));
mRecyclerView.addItemDecoration(new StickyRecyclerHeadersDecoration(mAdapter));
StickyRecyclerHeadersTouchListener
allows you to listen for clicks on header views.
Simply create an instance of StickyRecyclerHeadersTouchListener
, set the OnHeaderClickListener
,
and add the StickyRecyclerHeadersTouchListener
as a touch listener to your RecyclerView
.
StickyRecyclerHeadersTouchListener touchListener =
new StickyRecyclerHeadersTouchListener(recyclerView, headersDecor);
touchListener.setOnHeaderClickListener(
new StickyRecyclerHeadersTouchListener.OnHeaderClickListener() {
@Override
public void onHeaderClick(View header, int position, long headerId) {
Toast.makeText(MainActivity.this, "Header position: " + position + ", id: " + headerId,
Toast.LENGTH_SHORT).show();
}
});
mRecyclerView.addOnItemTouchListener(touchListener);
The StickyHeaders aren't aware of your adapter so if you must notify them when your data set changes.
mAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
@Override public void onChanged() {
headersDecor.invalidateHeaders();
}
});
If the Recyclerview's layout manager implements getExtraLayoutSpace (to preload more content then is visible for performance reasons), you must implement ItemVisibilityAdapter and pass an instance as a second argument to StickyRecyclerHeadersDecoration's constructor.
@Override
public boolean isPositionVisible(final int position) {
return layoutManager.findFirstVisibleItemPosition() <= position
&& layoutManager.findLastVisibleItemPosition() >= position;
}
Item animators don't play nicely with RecyclerView decorations, so your mileage with that may vary.
API 11+
-
The header views aren't recycled at this time. Contributions are most welcome.
-
I haven't tested this with ItemAnimators yet.
-
The header views are drawn to a canvas, and are not actually a part of the view hierarchy. As such, they can't have touch states, and you may run into issues if you try to load images into them asynchronously.
0.4.3 (12/24/2015) - Change minSDK to 11, fix issue with header bounds caching
0.4.2 (8/21/2015) - Add support for reverse ReverseLayout
in LinearLayoutManager
by AntonPukhonin
0.4.1 (6/24/2015) - Fix "dancing headers" by DarkJaguar91
0.4.0 (4/16/2015) - Code reorganization by danoz73, fixes for different sized headers, performance improvements
0.3.6 (1/30/2015) - Prevent header clicks from passing on the touch event
0.3.5 (12/12/2014) - Add StickyRecyclerHeadersDecoration.invalidateHeaders() method
0.3.4 (12/3/2014) - Fix issues with rendering of header views with header ID = 0
0.3.3 (11/13/2014) - Fixes for padding, support views without headers
0.3.2 (11/1/2014) - Bug fixes for list items with margins and deleting items
0.2 (10/3/2014) - Add StickyRecyclerHeadersTouchListener
0.1 (10/2/2014) - Initial Release