Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RecyclerView header and footer

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

like image 429
Sandra Avatar asked Oct 27 '14 10:10

Sandra


People also ask

What is RecyclerView layout?

RecyclerView makes it easy to efficiently display large sets of data. You supply the data and define how each item looks, and the RecyclerView library dynamically creates the elements when they're needed. As the name implies, RecyclerView recycles those individual elements.


2 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.

like image 171
Bronx Avatar answered Sep 24 '22 06:09

Bronx


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();         }     } } 
like image 23
David Medenjak Avatar answered Sep 23 '22 06:09

David Medenjak