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
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.
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.
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(); } } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With