RecyclerView header and footer

AndroidHeaderFooterAndroid 5.0-LollipopAndroid Recyclerview

Android Problem Overview


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

Android Solutions


Solution 1 - Android

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.

Solution 2 - Android

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();
        }
    }
}

Solution 3 - Android

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))

Solution 4 - Android

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:

Preview

Solution 5 - Android

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.

Solution 6 - Android

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();
    }
}
}      

Solution 7 - Android

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.

Solution 8 - Android

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();

Solution 9 - Android

For Sectioned LinearView headings with GridView items in Recyclerview:-

Check SectionedGridRecyclerViewAdapter

enter image description here

Solution 10 - Android

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" />

Solution 11 - Android

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:

enter image description here

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);

Solution 12 - Android

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSandraView Question on Stackoverflow
Solution 1 - AndroidBronxView Answer on Stackoverflow
Solution 2 - AndroidDavid MedenjakView Answer on Stackoverflow
Solution 3 - AndroidSean BlahoviciView Answer on Stackoverflow
Solution 4 - Androidlopez.mikhaelView Answer on Stackoverflow
Solution 5 - AndroidDarishView Answer on Stackoverflow
Solution 6 - AndroidTrunks ssjView Answer on Stackoverflow
Solution 7 - AndroidRaktim BhattacharyaView Answer on Stackoverflow
Solution 8 - AndroidF.WillView Answer on Stackoverflow
Solution 9 - AndroidHarpreetView Answer on Stackoverflow
Solution 10 - Androidlenhuy2106View Answer on Stackoverflow
Solution 11 - AndroidGustavoView Answer on Stackoverflow
Solution 12 - AndroidXiongView Answer on Stackoverflow