RecyclerView
class source code, it's a subclass of ViewGroup
and implements ScrollingView
and NestedScrollingChild
interfaces. It mean that the RecyclerView
structure is not like ListView
or GridView
(which is sub-classes of AdapterView
), it is a list view without the first and last points. Therefore, adding header/footer view to
RecyclerView
is not simple like the ListView
(by calling addHeaderView(View v)
or addFooterView(View v)
methods). To accomplish this, we must use a custom way.Through this post, I'll provide a solution to add the header/footer layout by determine the property of header, footer and list item in the adapter class, Accordingly, we will inflate suitable layout for each view. For another ways, please keep search on Internet!
DEMO VIDEO:
Declaring layouts for item/header/footer views
RecyclerView
:
layout_item.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="6dp">
<TextView
android:id="@+id/recycler_item_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="@dimen/activity_horizontal_margin"
android:text="Recycler View Item"
android:textStyle="bold" />
</android.support.v7.widget.CardView>
layout_footer.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp">
<TextView
android:id="@+id/footer_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/holo_orange_dark"
android:gravity="center"
android:padding="@dimen/activity_horizontal_margin"
android:text="Footer View"
android:textAllCaps="true"
android:textColor="@android:color/white"
android:textStyle="bold" />
</LinearLayout>
layout_header.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_marginBottom="10dp"
android:layout_height="wrap_content">
<TextView
android:id="@+id/header_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_dark"
android:gravity="center"
android:padding="@dimen/activity_horizontal_margin"
android:text="Header View"
android:textAllCaps="true"
android:textColor="@android:color/white"
android:textStyle="bold" />
</LinearLayout>
Configuration in adapter class
RecyclerView.Adapter
to custom an our own RecyclerView
adapter. Firstly, provide some static constants:
private static final int TYPE_HEADER = 0;
private static final int TYPE_FOOTER = 1;
private static final int TYPE_ITEM = 2;
In onCreateViewHolder()
method, create a ViewHolder
pattern and assign the layout to be shown based on the view type changes:
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_ITEM) {
//Inflating recycle view item layout
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_item, parent, false);
return new ItemViewHolder(itemView);
} else if (viewType == TYPE_HEADER) {
//Inflating header view
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_header, parent, false);
return new HeaderViewHolder(itemView);
} else if (viewType == TYPE_FOOTER) {
//Inflating footer view
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_footer, parent, false);
return new FooterViewHolder(itemView);
} else return null;
}
Most important, you must override getItemViewType()
to fix the header at zeroth position and footer at last position of the RecyclerView
:
@Override
public int getItemViewType(int position) {
if (position == 0) {
return TYPE_HEADER;
} else if (position == stringArrayList.size() + 1) {
return TYPE_FOOTER;
}
return TYPE_ITEM;
}
Eventually add the total array count by 2 to represent view that the RecyclerView
has to be inflated with header and footer layouts, you must rewrite getItemCount()
:
@Override
public int getItemCount() {
return stringArrayList.size() + 2;
}
Finally, the complete code of the adapter class would be like:
RecyclerViewAdapter.java
package info.devexchanges.recyclerviewheaderfooter;
import android.app.Activity;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int TYPE_HEADER = 0;
private static final int TYPE_FOOTER = 1;
private static final int TYPE_ITEM = 2;
private ArrayList<String> stringArrayList;
private Activity activity;
public RecyclerViewAdapter(Activity activity, ArrayList<String> strings) {
this.activity = activity;
this.stringArrayList = strings;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_ITEM) {
//Inflating recycle view item layout
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_item, parent, false);
return new ItemViewHolder(itemView);
} else if (viewType == TYPE_HEADER) {
//Inflating header view
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_header, parent, false);
return new HeaderViewHolder(itemView);
} else if (viewType == TYPE_FOOTER) {
//Inflating footer view
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_footer, parent, false);
return new FooterViewHolder(itemView);
} else return null;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
if (holder instanceof HeaderViewHolder) {
HeaderViewHolder headerHolder = (HeaderViewHolder) holder;
headerHolder.headerTitle.setText("Header View");
headerHolder.headerTitle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(activity, "You clicked at Header View!", Toast.LENGTH_SHORT).show();
}
});
} else if (holder instanceof FooterViewHolder) {
FooterViewHolder footerHolder = (FooterViewHolder) holder;
footerHolder.footerText.setText("Footer View");
footerHolder.footerText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(activity, "You clicked at Footer View", Toast.LENGTH_SHORT).show();
}
});
} else if (holder instanceof ItemViewHolder) {
ItemViewHolder itemViewHolder = (ItemViewHolder) holder;
itemViewHolder.itemText.setText("Recycler Item " + position);
itemViewHolder.itemText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(activity, "You clicked at item " + position, Toast.LENGTH_SHORT).show();
}
});
}
}
@Override
public int getItemViewType(int position) {
if (position == 0) {
return TYPE_HEADER;
} else if (position == stringArrayList.size() + 1) {
return TYPE_FOOTER;
}
return TYPE_ITEM;
}
@Override
public int getItemCount() {
return stringArrayList.size() + 2;
}
private class HeaderViewHolder extends RecyclerView.ViewHolder {
TextView headerTitle;
public HeaderViewHolder(View view) {
super(view);
headerTitle = (TextView) view.findViewById(R.id.header_text);
}
}
private class FooterViewHolder extends RecyclerView.ViewHolder {
TextView footerText;
public FooterViewHolder(View view) {
super(view);
footerText = (TextView) view.findViewById(R.id.footer_text);
}
}
private class ItemViewHolder extends RecyclerView.ViewHolder {
TextView itemText;
public ItemViewHolder(View itemView) {
super(itemView);
itemText = (TextView) itemView.findViewById(R.id.recycler_item_text);
}
}
}
NOTE
: You must add RecyclerView
and CarView
dependencies to app-level build.gradle to use these 2 widgets:
compile 'com.android.support:recyclerview-v7:25.0.0'
compile 'com.android.support:cardview-v7:25.0.0'
compile 'com.android.support:appcompat-v7:25.0.0'
Running application
Conclusions
RecyclerView
easily. I hope this post is helpful with beginners which starting using RecyclerView
instead of ListView
. For more posts about this flexible widget, please visit this tag link. Finally, you can get full code by click at the button below.