The Open Event Android project has a fragment for showing sponsors of the event. Each Sponsor model has a name, url, type and level. The SponsorsFragment shows list according to type and level. Each sponsor list item has sponsor type TextView. There can be more than one sponsors with the same type. So instead of showing type in the Sponsor item we can add Sticky header showing type at the top which will group the sponsors with the same type and also gives the great UI. In this post I explain how to add the Sticky headers in the RecyclerView using StickyHeadersRecyclerView library.
1. Add dependency
In order to use Sticky Headers in your app add following dependencies in your app module’s build.gradle file.
dependencies { compile 'com.timehop.stickyheadersrecyclerview:library:0.4.3' }
2. Create layout for header
Create recycler_view_header.xml file for the header. It will contain LinearLayout and simple TextView which will show Sponsor type.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/recyclerview_view_header" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="@dimen/padding_medium" /> </LinearLayout>
Here you can modify layout according to your need.
3. Implement StickyRecyclerHeadersAdapter
Now implement StickyRecyclerHeadersAdapter in the List Adapter. Override getHeaderId(), onCreateHeaderViewHolder(), onBindHeaderViewHolder
() methods of the StickyRecyclerHeadersAdapter.
public class SponsorsListAdapter extends BaseRVAdapter<Sponsor, SponsorViewHolder> implements StickyRecyclerHeadersAdapter { ... @Override public long getHeaderId(int position) {...} @Override public RecyclerView.ViewHolder onCreateHeaderViewHolder(ViewGroup parent) {...} @Override public void onBindHeaderViewHolder(RecyclerView.ViewHolder holder, int position) {...} }
The getHeaderId() method is used to give an id to the header. It is the main part of the implementation here all the sponsors with the same type should return the same id. In our case we are returning sponsor level because all the sponsor types have corresponding levels.
String level = getItem(position).getLevel(); return Long.valueOf(level);
The onCreateHeaderViewHolder() returns Recycler ViewHolder for the header. Here we will use in the inflate() method of LayoutInflater to get View object of recycler_view_header.xml file. Then return new RecyclerView.ViewHolder object using View object.
View view = LayoutInflater.from(parent.getContext()) .inflate(R.layout.recycler_view_header, parent, false); return new RecyclerView.ViewHolder(view) {};
The onBindHeaderViewHolder() binds the sponsor to HeaderViewHolder. In this method we sets the sponsor type string to the TextView we have created in the recycler_view_header.xml file.
TextView textView = (TextView) holder.itemView.findViewById(R.id.recyclerview_view_header); textView.setGravity(Gravity.CENTER_HORIZONTAL); String sponsorType = getItem(position).getType(); if (!Utils.isEmpty(sponsorType)) textView.setText(sponsorType.toUpperCase());
Here you can also modify TextView according to your need. We are centering text using setGravity() method.
4. Setup RecyclerView
Now create RecyclerView and set adapter using setAdapter() method. Also as we want the linear list of sponsors so set the LinearLayoutManager using setLayoutManager() method.
SponsorsListAdapter sponsorsListAdapter = new SponsorsListAdapter(getContext(), sponsors); sponsorsRecyclerView.setAdapter(sponsorsListAdapter); sponsorsRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
Create StickyRecyclerHeadersDecoration object and add it in the RecyclerView using addItemDecoration() method.
final StickyRecyclerHeadersDecoration headersDecoration = new StickyRecyclerHeadersDecoration(sponsorsListAdapter); sponsorsRecyclerView.addItemDecoration(headersDecoration); sponsorsListAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver(){ @Override public void onChanged { headersDecoration.invalidateHeaders(); } });
Now add AdapterDataObserver using registerAdapterDataObserver() method. The onChanged() method in this observer is called whenever dataset changes. So in this method invalidate headers using invalidateHeaders() method of HeaderDecoration.
Now we are all set. Run the app it will look like this.
Conclusion
Sticky headers in the App gives great UI and UX. You can also add a click listener to the headers. To know more about Sticky Headers follow the links given below.
- StickyHeadersRecyclerView: https://github.com/timehop/sticky-headers-recyclerview
- Tutorial with grid layout: https://matalamaki.fi/2015/09/24/implementing-sticky-recyclerview-grid-headers-on-android/
- Open Event Android PR: https://github.com/fossasia/open-event-android/pull/1864