In ListView, you can add the head and tail, and the method is very simple. You can call listview.addHeaderView(view); and listview.addFooterView(view); directly, but there is no such method in RecyclerView, so how to use this method in RecyclerView? This is the point of this article.
principle
Looking at the source code of ListView, we know that its head and tail, in essence, add a head and a tail to the original adapter, that is, wrap a layer, so if we want to use the head and tail in RecyclerView, we can make a head and tail according to the method of ListView, and draw a ladle to make a head and tail.
Realization
Customize a RecyclerView layout to add headers and tails
public class WrapRecyclerView extends RecyclerView { private ArrayList<View> mHeaderViewInfos = new ArrayList<View>(); private ArrayList<View> mFooterViewInfos = new ArrayList<View>(); private Adapter mAdapter; public WrapRecyclerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public void addHeaderView(View v) { mHeaderViewInfos.add(v); if (mAdapter != null) { if (!(mAdapter instanceof HeaderViewRecyclerAdapter)) { mAdapter = new HeaderViewRecyclerAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter); } } } public void addFooterView(View v) { mFooterViewInfos.add(v); if (mAdapter != null) { if (!(mAdapter instanceof HeaderViewRecyclerAdapter)) { mAdapter = new HeaderViewRecyclerAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter); } } } @Override public void setAdapter(Adapter adapter) { if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) { mAdapter = new HeaderViewRecyclerAdapter(mHeaderViewInfos, mFooterViewInfos, adapter); } else { mAdapter = adapter; } super.setAdapter(mAdapter); } }
The adapters used in the layout
public class HeaderViewRecyclerAdapter extends Adapter { private Adapter mAdapter; ArrayList<View> mHeaderViewInfos; ArrayList<View> mFooterViewInfos; public HeaderViewRecyclerAdapter(ArrayList<View> headerViewInfos, ArrayList<View> footerViewInfos, Adapter adapter) { mAdapter = adapter; if (headerViewInfos == null) { mHeaderViewInfos = new ArrayList<View>(); } else { mHeaderViewInfos = headerViewInfos; } if (footerViewInfos == null) { mFooterViewInfos = new ArrayList<View>(); } else { mFooterViewInfos = footerViewInfos; } } @Override public int getItemCount() { if (mAdapter != null) { return getFootersCount() + getHeadersCount() + mAdapter.getItemCount(); } else { return getFootersCount() + getHeadersCount(); } } @Override public void onBindViewHolder(ViewHolder holder, int position) { int numHeaders = getHeadersCount(); //head if (position < numHeaders) { return; } //body final int adjPosition = position - numHeaders; int adapterCount = 0; if (mAdapter != null) { adapterCount = mAdapter.getItemCount(); if (adjPosition < adapterCount) { mAdapter.onBindViewHolder(holder, adjPosition); return; } } //footer } @Override public int getItemViewType(int position) { //Determine what type of current entry is int numHeaders = getHeadersCount(); if (position < numHeaders) { return RecyclerView.INVALID_TYPE; } final int adjPosition = position - numHeaders; int adapterCount = 0; if (mAdapter != null) { adapterCount = mAdapter.getItemCount(); if (adjPosition < adapterCount) { return mAdapter.getItemViewType(adjPosition); } } return RecyclerView.INVALID_TYPE - 1; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { //header if (viewType == RecyclerView.INVALID_TYPE) { return new HeaderViewHolder(mHeaderViewInfos.get(0)); } else if (viewType == RecyclerView.INVALID_TYPE - 1) {//footer return new HeaderViewHolder(mFooterViewInfos.get(0)); } //Footer return mAdapter.onCreateViewHolder(parent, viewType); } public int getHeadersCount() { return mHeaderViewInfos.size(); } public int getFootersCount() { return mFooterViewInfos.size(); } private static class HeaderViewHolder extends ViewHolder { public HeaderViewHolder(View view) { super(view); } } }
Use the added custom layout in the layout file
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <com.cj5785.wraprecyclerview.WrapRecyclerView android:id="@+id/wrap_recyclerview" android:layout_width="match_parent" android:layout_height="match_parent"/> </RelativeLayout>
Writing adapters
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> { private List<String> list; public MyAdapter(List<String> list) { this.list = list; } class MyViewHolder extends RecyclerView.ViewHolder{ private TextView textView; public MyViewHolder(View view) { super(view); textView = (TextView) view.findViewById(R.id.tv); } } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); View view = layoutInflater.inflate(R.layout.list_item,parent,false); MyViewHolder holder = new MyViewHolder(view); return holder; } @Override public void onBindViewHolder(MyViewHolder holder, int position) { holder.textView.setText(list.get(position)); } @Override public int getItemCount() { return list.size(); } }
Item layout of adapters
<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/tv" android:layout_marginTop="10dp" android:layout_marginBottom="10dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" />
The main activity is invoked
public class MainActivity extends AppCompatActivity { private WrapRecyclerView wrapRecyclerView; private LayoutParams params; private List<String> list; private MyAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); wrapRecyclerView = (WrapRecyclerView) findViewById(R.id.wrap_recyclerview); params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); TextView header = new TextView(this); header.setGravity(Gravity.CENTER); header.setLayoutParams(params); header.setText("Header"); wrapRecyclerView.addHeaderView(header); TextView footer = new TextView(this); footer.setGravity(Gravity.CENTER); footer.setLayoutParams(params); footer.setText("Footer"); wrapRecyclerView.addFooterView(footer); list = new ArrayList<>(); for (int i = 0; i < 10; i++) { list.add("item " + i); } adapter = new MyAdapter(list); wrapRecyclerView.setLayoutManager(new LinearLayoutManager(this)); wrapRecyclerView.setAdapter(adapter); } }
Operation result