Maybe this question has been asked before, but I could not seem to find a precise answer or solution. I started using the RecyclerView, and I implemented it using the LinearLayoutManager. Now I want to add custom header and footer items, that differ from the rest of the items in my RecyclerView. The header and footer should not be sticky, I want them to scroll with the rest of the items. Can somebody point out some example how to do this or just share ideas. I will appreciate it very much. Thx
-
see int RecyclerView.Adapter.getItemViewType(int position) – pskink Oct 27 '14 at 11:05
-
Can u post some code example, I'm not sure how to do this... – Sandra Oct 27 '14 at 13:22
-
override that method, for position == 0 return 0 for any other position return 1, now onCreateViewHolder will be called with two different viewTypes: 0 for header view and 1 for "nornal" view – pskink Oct 27 '14 at 13:48
-
see this answer it has an example http://stackoverflow.com/a/26573338/2127203 – EC84B4 Oct 27 '14 at 14:51
-
thx @hister, I will take a look at the example... – Sandra Oct 27 '14 at 16:46
-
the example that @hister provided did the trick for me – Sandra Nov 13 '14 at 09:57
-
@pskink This would work only for LinearLayoutManager, but what about GridLayoutManager ? I think it's better to use something like that: http://stackoverflow.com/questions/26869312/set-span-for-items-in-gridlayoutmanager-using-spansizelookup – android developer Dec 30 '14 at 12:39
-
@androiddeveloper so use spans – pskink Dec 30 '14 at 12:44
-
@pskink I don't understand. The link I've given handles spans too, no? do you have a different idea? – android developer Dec 30 '14 at 12:45
-
@androiddeveloper if you have for example 3 columns in your grid then return 3 in getSpanSize for position 0 otherwise return 1 – pskink Dec 30 '14 at 13:07
-
@pskink Yes. But it's still not quite like headers on ListViews, no? What happens if you wish to add swipeToRefresh, but it should show beneath the header itself (like on Google Now Launcher) ? Is it still possible? – android developer Dec 30 '14 at 13:14
-
@androiddeveloper i don't think i understand what you mean – pskink Dec 30 '14 at 13:17
-
@pskink Open Google Now Launcher, then go to the left (in the home screens). Now, swipe up to refresh. You will see that the progress bar that appears will be shown beneath the header. – android developer Dec 30 '14 at 13:31
-
@androiddeveloper it all depends how you will implement your RecyclerView.Adapter, it adapts your data model to a presentation view, so you can do whatever you want – pskink Dec 30 '14 at 21:46
-
@pskink I see. In fact, the swipe-to-refresh has changed its style. now it's just a rotating circle, and as far as I remember it also supports recyclerView... – android developer Dec 30 '14 at 22:34
-
Possible duplicate of [Android 5.0 - Add header/footer to a RecyclerView](http://stackoverflow.com/questions/26448717/android-5-0-add-header-footer-to-a-recyclerview) – Reaz Murshed Apr 21 '16 at 10:03
-
issue in remove product with that http://stackoverflow.com/questions/38222410/recyclerview-with-footer-not-able-to-delete-last-item – Aditya Vyas-Lakhan Jul 06 '16 at 11:27
12 Answers
in your adapter add this class:
private class VIEW_TYPES {
public static final int Header = 1;
public static final int Normal = 2;
public static final int Footer = 3;
}
then Override the following method like this:
@Override
public int getItemViewType(int position) {
if(items.get(position).isHeader)
return VIEW_TYPES.Header;
else if(items.get(position).isFooter)
return VIEW_TYPES.Footer;
else
return VIEW_TYPES.Normal;
}
Now in the onCreateViewHolder method inflate your layout based on the view type::
@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View rowView;
switch (i) {
case VIEW_TYPES.Normal:
rowView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.normal, viewGroup, false);
break;
case VIEW_TYPES.Header:
rowView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.header, viewGroup, false);
break;
case VIEW_TYPES.Footer:
rowView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.footer, viewGroup, false);
break;
default:
rowView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.normal, viewGroup, false);
break;
}
return new ViewHolder (rowView);
}
Now in the onBindViewHolder method bind your layout based on the view holder:
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
int viewType = getItemViewType(position);
switch(viewType) {
case VIEW_TYPES.Header: // handle row header
break;
case VIEW_TYPES.Footer: // handle row footer
break;
case VIEW_TYPES.Normal: // handle row item
break;
}
}
Hope this can help.

- 4,480
- 4
- 34
- 44
-
I could implement the header fine but when I added the footer its getting inserted after the first item of the Recycler view though I specified the Footer attribute as "layout_alignParentBottom=true". Any idea what might be the reason? – AndroidDev Apr 01 '15 at 12:39
-
2Hi, header and footer are item too, so you have to add the header first (checking that it is in the first position) then add your items and finally in the last position add the footer – Bronx Apr 02 '15 at 10:23
-
Thanks for this solution but can you tell me where is the methods name, "isHeader" and "isFooter" ? @Bronx – Ronak Joshi Jul 30 '15 at 13:50
-
Hi @RonakJoshi isHeader and isFooter are not methods, they are variables you have in the items of your list. For example you have a class named MyItem and the constructor is public MyItem(Object myObject, boolean isHeader, boolean isFooter) – Bronx Jul 31 '15 at 08:03
-
-
I keep getting 'cannot resolve symbol .isHeader'. Also 'method call expected' for 'return new ViewHolder (rowView);' The solution doesn't work for me. – Martin Erlic Dec 24 '15 at 03:06
-
Hi @bluemunch, check my previous answer to RonakJoshi, isHeader is a parameter you must have in your item class. This was an example, you can use whatever logic you want to choose which item is the header or the footer. – Bronx Jan 05 '16 at 10:46
-
-
1@Bronx or add the full code because I am still having the same issue santafebound is having. – X09 Mar 30 '17 at 15:53
-
seems promising. But need a full code. as Such I'm using Kotlin and didn't find items.get(position).isHeader (isHeader) property here. As well I am looking to put "Load more" button at the footer. So on click event also need to handle somewhere. Please help! – meekash55 Jul 06 '21 at 09:23
This is very easy with ItemDecorations and without modifying any other code:
recyclerView.addItemDecoration(new HeaderDecoration(this,
recyclerView, R.layout.test_header));
Reserve some space for drawing, inflate the layout you want drawn and draw it in the reserved space.
The code for the Decoration:
public class HeaderDecoration extends RecyclerView.ItemDecoration {
private View mLayout;
public HeaderDecoration(final Context context, RecyclerView parent, @LayoutRes int resId) {
// inflate and measure the layout
mLayout = LayoutInflater.from(context).inflate(resId, parent, false);
mLayout.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
// layout basically just gets drawn on the reserved space on top of the first view
mLayout.layout(parent.getLeft(), 0, parent.getRight(), mLayout.getMeasuredHeight());
for (int i = 0; i < parent.getChildCount(); i++) {
View view = parent.getChildAt(i);
if (parent.getChildAdapterPosition(view) == 0) {
c.save();
final int height = mLayout.getMeasuredHeight();
final int top = view.getTop() - height;
c.translate(0, top);
mLayout.draw(c);
c.restore();
break;
}
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (parent.getChildAdapterPosition(view) == 0) {
outRect.set(0, mLayout.getMeasuredHeight(), 0, 0);
} else {
outRect.setEmpty();
}
}
}

- 33,993
- 14
- 106
- 134
-
1how can you add click handling in item decorator? I have to add a button as header, its can be seen with your code but I am unable to add on click as findViewById return null – chin87 Nov 23 '15 at 12:04
-
1@chin87 ...since `mLayout` is a view - just add it to the view? Either add a getter or modify the constructor. (And it depends where you call findViewById...Since the view is neither attached to the recyclerView nor to the fragment) – David Medenjak Nov 23 '15 at 12:06
-
2How do you use it to add a footer? Will it also work when LinearLayoutManager is horizontal? – android developer Mar 07 '16 at 12:18
-
@androiddeveloper you would have to modify or adapt the code, this sample is more proof of concept. to use it as footer you would check for last item rather than `position == 0` and draw beneath instead of above, for using it horizontally, you would also need to adapt it, modifying the drawing for left/right instead of above – David Medenjak Mar 07 '16 at 13:35
-
@DavidMedenjak That's too bad. Do you know perhaps of a repo that has them all? Are there any disadvantages of using your solution, other than the need of extra code for each header&footer for horizontal&vertical – android developer Mar 07 '16 at 14:42
-
@androiddeveloper The only real downside is, that it is just a decoration. You won't be able to add onClick to it. I don't know of any full implementations, but modifying the code for all 4 cases is not too hard. You can find the repo that I play around with including more samples at https://github.com/bleeding182/recyclerviewItemDecorations – David Medenjak Mar 07 '16 at 14:48
-
@DavidMedenjak Why can't I add onClick to it? because it has no real view, as it only draws stuff? Is it a lot of changes to the current code? Maybe it's better to just add parameters to the decorator, instead of creating new, similar classes. – android developer Mar 07 '16 at 14:54
-
@DavidMedenjak Also, suppose I want to remove the header at some point, will it have a nice animation like of normal items of the RecyclerView (when they have an id) ? Or will it just disappear right away? – android developer Mar 07 '16 at 15:22
-
@androiddeveloper you don't get any animation for free. you can use the childs alpha and translation to animate with the child, I wrote an article on that here: http://bleeding182.blogspot.com/2015/11/animations-and-decorations.html – David Medenjak Mar 07 '16 at 16:39
-
@DavidMedenjak The article is about normal items. You mean the same holds for decorators too? – android developer Mar 07 '16 at 22:36
-
Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/105656/discussion-between-david-medenjak-and-android-developer). – David Medenjak Mar 08 '16 at 09:39
-
Very helpful? but I faced of with another problem. I've added progress bar in header but it animates only when I move list or call notifydatasetchange() – Dima May 14 '16 at 13:24
-
@Dima Yes. This is not a classic View, it's just some drawing on top. If you change it you will have to find a way to invalidate it yourself and update the recyclerview. The main use case of the presented answer is to show some image or text as a header – David Medenjak May 14 '16 at 13:26
-
I've attempted your answer but I can't get it to work. How simple is your `R.layout.test_header`? The layout I am attempting to add is a bit more complex. LinearLayout and stuff. Is this not possible? – Andy Dec 01 '17 at 15:21
-
@Andy it really depends. Try using a fixed height/width and see if that helps, maybe it can't be properly measured/layouted. But I'd try to keep it simple – David Medenjak Dec 01 '17 at 17:12
-
I use a TextView as a footer layout and it makes no new lines, just draws single line textview which goes out of bounds – Leo DroidCoder Dec 25 '17 at 12:13
-
If someones looking for the footer version: https://gist.github.com/dreiklangdev/4b092eade09feb26bdf1c090fd2e5643 – lenhuy2106 Jul 16 '18 at 19:47
-
-
@DavidMedenjak This works fine but the layout inside the header is clipped right side – Jarin Rocks Aug 05 '22 at 12:06
If all you need is a blank header and footer, here is a very simple way to achieve this (written in Kotlin):
class HeaderFooterDecoration(private val headerHeight: Int, private val footerHeight: Int) : RecyclerView.ItemDecoration() {
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
val adapter = parent.adapter ?: return
when (parent.getChildAdapterPosition(view)) {
0 -> outRect.top = headerHeight
adapter.itemCount - 1 -> outRect.bottom = footerHeight
else -> outRect.set(0, 0, 0, 0)
}
}
}
Call it this way:
recyclerView.addItemDecoration(HeaderFooterDecoration(headerHeightPx, footerHeightPx))

- 5,350
- 4
- 28
- 38
-
1Not very often that I find the best solution way down here. Short Concise, readable, gets the job done. Full Marks Sean :D – AMAN77 Aug 20 '19 at 07:11
-
A very good example with source code to create RecyclerView with header and footer https://www.loopwiki.com/ui-ux-design/recyclerview-with-header-and-footer-android-example/ – Amar Yadav Sep 09 '20 at 06:23
You can use this GitHub] library to add a Header or Footer to your RecyclerView
in the simplest way possible.
You need to add the HFRecyclerView library in your project or you can also grab it from Gradle:
compile 'com.mikhaellopez:hfrecyclerview:1.0.0'
This library is based on a work at @hister
This is a result in image:

- 1
- 1

- 9,943
- 19
- 67
- 110
recyclerview:1.2.0 introduces ConcatAdapter
ConcatAdapter is a new RecyclerView Adapter that can combine multiple adapters linearly.
How to use ConcatAdapter?
add following dependency into your build.gradle
file
androidx.recyclerview:recyclerview:1.2.0-alpha04
Then, if you have multiple adapters, you can easily merge them using
MyAdapter adapter1 = ...;
AnotherAdapter adapter2 = ...;
ConcatAdapter merged = new ConcatAdapter(adapter1, adapter2);
recyclerView.setAdapter(merged);
For the sample above, ConcatAdapter will present items from adapter1 followed by adapter2.
Here you can find the complete documentation.
Find complete working sample here.
Read this article for more info.
Here you can find the source code.

- 11,032
- 5
- 50
- 70
here some header itemdecoration for recyclerview
withsome modification you can change to footer
public class HeaderItemDecoration extends RecyclerView.ItemDecoration {
private View customView;
public HeaderItemDecoration(View view) {
this.customView = view;
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
customView.layout(parent.getLeft(), 0, parent.getRight(), customView.getMeasuredHeight());
for (int i = 0; i < parent.getChildCount(); i++) {
View view = parent.getChildAt(i);
if (parent.getChildAdapterPosition(view) == 0) {
c.save();
final int height = customView.getMeasuredHeight();
final int top = view.getTop() - height;
c.translate(0, top);
customView.draw(c);
c.restore();
break;
}
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (parent.getChildAdapterPosition(view) == 0) {
customView.measure(View.MeasureSpec.makeMeasureSpec(parent.getMeasuredWidth(), View.MeasureSpec.AT_MOST),
View.MeasureSpec.makeMeasureSpec(parent.getMeasuredHeight(), View.MeasureSpec.AT_MOST));
outRect.set(0, customView.getMeasuredHeight(), 0, 0);
} else {
outRect.setEmpty();
}
}
}

- 91
- 1
- 5
-
Your code came out really handy, but I tried modifying it for footer by changing parent.getChildAdapterPosition(view) == 0 to parent.getChildAdapterPosition(view) == parent.getAdapter().getItemCount() But it didn;t work. Well, it does work for any other position in between, but not the last one, could you suggest any changes? – Anurag Bhalekar Oct 21 '20 at 13:34
-
Thanks a lot @Trunks! In my case I have added a simple header containing only a TextView in this way: `recyclerView.addItemDecoration(new HeaderItemDecoration(aTextView), 0)`. – Umberto Covino Feb 20 '21 at 19:06
-
1@AnuragBhalekar it's parent.getChildAdapterPosition(view) == (parent.getAdapter().getItemCount()-1) – Driss Bounouar Oct 04 '21 at 12:41
I would suggest not to customize rv adapater.
Keep it as it as...in your rv item layout just add the footer with the layout and set the visisbilty gone.
Then when you reach the last item in adapter...make it visible.
and when you try this make sure you add this to your rv adapter.
@Override
public void onBindViewHolder(final PersonViewHolder personViewHolder, int i) {
if(i==List.size()) // Last item in recycle view
personViewHolder.tv_footer.setVisibility(VISIBLE);// Make footer visible now }
@Override
public int getItemViewType(int position) {
return position;
}
Do the same for Header. Here i==0 // first item of list
Easiest solution to me.

- 59
- 4
-
Okay, your approach is straightforward. But, isn't it a waste of memory to have the view as `View.GONE` for most of the time? – Kathir Dec 05 '18 at 17:03
-
@Kathir...it is processed only when its visible in the screen area...other time it is treated and kept in background as usual array of records to be shown.. – Raktim Bhattacharya Dec 08 '18 at 04:25
-
Thank you @Raktim. I found a relevant question [answering](https://stackoverflow.com/a/17883768/7551190) that. In short, it still takes up memory comparing to what not having that view would be consuming but it's better than `View.INVISIBLE`. Also, read [this](https://stackoverflow.com/a/17883749/7551190) to understand when to use `View.INVISIBLE` instead – Kathir Dec 08 '18 at 04:33
Click here. I did a extension of RecyclerView.Adapter. Easy to add header and footer.
class HFAdapter extends HFRecyclerViewAdapter<String, HFAdapter.DataViewHolder>{
public HFAdapter(Context context) {
super(context);
}
@Override
public DataViewHolder onCreateDataItemViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.data_item, parent, false);
return new DataViewHolder(v);
}
@Override
public void onBindDataItemViewHolder(DataViewHolder holder, int position) {
holder.itemTv.setText(getData().get(position));
}
class DataViewHolder extends RecyclerView.ViewHolder{
TextView itemTv;
public DataViewHolder(View itemView) {
super(itemView);
itemTv = (TextView)itemView.findViewById(R.id.itemTv);
}
}
}
//add header
View headerView = LayoutInflater.from(this).inflate(R.layout.header, recyclerView, false);
hfAdapter.setHeaderView(headerView);
//add footer
View footerView = LayoutInflater.from(this).inflate(R.layout.footer, recyclerView, false);
hfAdapter.setFooterView(footerView);
//remove
hfAdapter.removeHeader();
hfAdapter.removeFooter();

- 46
- 2
For Sectioned LinearView headings with GridView items in Recyclerview:-
One other way would be wrapping header and reyclerview in a coordinatorlayout:
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:elevation="0dp">
<View
android:id="@+id/header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll" />
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />

- 313
- 3
- 8
You can use the library SectionedRecyclerViewAdapter, it has the concept of "Sections", where which Section has a Header, Footer and Content (list of items). In your case you might only need one Section but you can have many:
1) Create a custom Section class:
class MySection extends StatelessSection {
List<String> myList = Arrays.asList(new String[] {"Item1", "Item2", "Item3" });
public MySection() {
// call constructor with layout resources for this Section header, footer and items
super(R.layout.section_header, R.layout.section_footer, R.layout.section_item);
}
@Override
public int getContentItemsTotal() {
return myList.size(); // number of items of this section
}
@Override
public RecyclerView.ViewHolder getItemViewHolder(View view) {
// return a custom instance of ViewHolder for the items of this section
return new MyItemViewHolder(view);
}
@Override
public void onBindItemViewHolder(RecyclerView.ViewHolder holder, int position) {
MyItemViewHolder itemHolder = (MyItemViewHolder) holder;
// bind your view here
itemHolder.tvItem.setText(myList.get(position));
}
}
2) Create a custom ViewHolder for the items:
class MyItemViewHolder extends RecyclerView.ViewHolder {
private final TextView tvItem;
public MyItemViewHolder(View itemView) {
super(itemView);
tvItem = (TextView) itemView.findViewById(R.id.tvItem);
}
}
3) Set up your ReclyclerView with the SectionedRecyclerViewAdapter
// Create an instance of SectionedRecyclerViewAdapter
SectionedRecyclerViewAdapter sectionAdapter = new SectionedRecyclerViewAdapter();
MySection mySection = new MySection();
// Add your Sections
sectionAdapter.addSection(mySection);
// Set up your RecyclerView with the SectionedRecyclerViewAdapter
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setAdapter(sectionAdapter);

- 6,583
- 5
- 40
- 71
May be GroupAdapter is what you want.
A specialized RecyclerView.Adapter that presents data from a sequence of RecyclerView.Adapter. The sequence is static but each adapter can be presented in zero or more item views. The child adapter can use ViewType safely. In addition, we can addHeaderView or addFooterView like ListView.

- 11
- 1