Mobile App Development: Tutorial How To Add Header to RecyclerView in Android

1 Star2 Stars3 Stars4 Stars5 Stars (6 votes, average: 4.83 out of 5)
Loading...

 

In the previous post, I showed you how to add header and footer to childview of an ExpandableListview. This article is also related to headers, but it’s about how to Add Header to RecyclerView.

RecyclerView is the upgrade of ListView and there are a lot of advantages compared to ListView such as CardView and ViewHolder. CardView allows us to create a complex and friendly UI easily while ViewHolder pattern helps to avoid looking up the UI components all the time the system shows a row. However, it does come with some disadvantages. One of the disadvantages is without support methods such as addHeaderView() or addFooterView() like a ListView do.

I tried to look around on the internet for a completed example showing how to add header to RecyclerView but I couldn’t find one. Here we share an example with you which will show you a header with a text on it and following it is a list of an image and its name.

This example is written in Android Studio with the version of 1.2.2.

 

Ho Ngoc Trang,  trangho214@gmail.com, is the author of this article and she contributes to RobustTechHouse Blog. 

 

 

1. Adding support library

To get RecyclerView and CardView to work on the previous version of Lollipop we need to add support libraries to gradle.

compile 'com.android.support:recyclerview-v7:22.2.0'
compile 'com.android.support:cardview-v7:22.2.0'

 

 

2. Creating RecyclerView

Using a RecyclerView instance is slightly more complicated. However, defining it in a layout XML file is quite simple. You can define it in a layout as follows:

main_activity.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:paddingLeft="@dimen/activity_horizontal_margin"
   android:paddingRight="@dimen/activity_horizontal_margin"
   android:paddingTop="@dimen/activity_vertical_margin"
   android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
   <android.support.v7.widget.RecyclerView
       android:id="@+id/my_recycler_view"
       android:scrollbars="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
   </android.support.v7.widget.RecyclerView>
</RelativeLayout>

 

 

3. Creating CardView

CardView in this case acts like a list_item. It holds all UI components we need for an item showed in the RecyclerView.

header_item.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:card_view="http://schemas.android.com/apk/res-auto"
   android:orientation="vertical" android:layout_width="match_parent"
   android:layout_height="match_parent">
   <android.support.v7.widget.CardView
       android:layout_width = "match_parent"
       android:layout_height = "wrap_content"
       card_view:contentPadding="@dimen/activity_horizontal_margin"
       card_view:cardCornerRadius="3dp">
       <TextView
           android:id="@+id/txtHeader"
           android:gravity="center"
           android:textColor="@android:color/primary_text_dark"
           android:background="@drawable/rectangle"
           android:textSize="@dimen/abc_text_size_large_material"
           android:layout_width="match_parent"
           android:layout_height="50dp" />
   </android.support.v7.widget.CardView>
</LinearLayout>

 

list_item.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:card_view="http://schemas.android.com/apk/res-auto"
   android:orientation="vertical"
   android:layout_width="match_parent"
   android:layout_height="match_parent">
   <android.support.v7.widget.CardView
       android:layout_width = "match_parent"
       android:layout_height = "wrap_content"
       android:layout_margin = "4dp"
       card_view:contentPadding="@dimen/activity_horizontal_margin"
       card_view:cardCornerRadius="3dp">
       <LinearLayout
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:orientation="vertical">
           <TextView
               android:id="@+id/txtName"
               android:text="abc"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content" />
           <ImageView
               android:layout_marginBottom="10dp"
               android:id="@+id/ivListItem"
               android:layout_width="match_parent"
               android:layout_height="wrap_content" />
       </LinearLayout>
   </android.support.v7.widget.CardView>
</LinearLayout>

 

 

4. Classes

We need two classes, which represents two objects working with header and list item.  I named these classes Header and ListItem. For simplicity, I just made the Header class with one field. However you can modify it to meet your needs by adding more fields or change the type of field. ListItem class has two fields – a name and an id. Id represents image and name is the name of image, which will show in each item of the list.

 

Header Class

public class Header {
//    More fields can be defined here after your need
   private String header;
  
   public Header(){}

   public String getHeader() {
       return header;
   }
   public void setHeader(String header) {
       this.header = header;
   }
}

 

ListItem Class

public class ListItem {

   private String name;

   public ListItem(){}

   public String getName() {
       return name;
   }

   public void setName(String name) {
       this.name = name;
   }

   private int id;

   public int getId() {
       return id;
   }

   public void setId(int id) {
       this.id = id;
   }
}

 

 

5. Custom Adapter

We will create an adapter for our RecyclerView. This adapter must extend RecyclerView.Adapter which is followed by a ViewHolder pattern. As mentioned above, ViewHolder will help the system avoid calling findViewById method every time it shows a row.

 

MyRecyclerAdapter class

public class MyRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private static final int TYPE_HEADER = 0;
    private static final int TYPE_ITEM = 1;

    Header header;
    List<ListItem> listItems;

    public MyRecyclerAdapter(Header header, List<ListItem> listItems)
    {
        this.header = header;
        this.listItems = listItems;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if(viewType == TYPE_HEADER)
        {
            View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.header_item, parent, false);
            return  new VHHeader(v);
        }
        else if(viewType == TYPE_ITEM)
        {
            View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false);
            return new VHItem(v);
        }
        throw new RuntimeException("there is no type that matches the type " + viewType + " + make sure your using types correctly");
    }

    private ListItem getItem(int position)
    {
        return listItems.get(position);
    }


    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if(holder instanceof VHHeader)
        {
            VHHeader VHheader = (VHHeader)holder;
            VHheader.txtTitle.setText(header.getHeader());
        }
        else if(holder instanceof VHItem)
        {
            ListItem currentItem = getItem(position-1);
            VHItem VHitem = (VHItem)holder;
            VHitem.txtName.setText(currentItem.getName());
            VHitem.iv.setBackgroundResource(currentItem.getId());
        }
    }

//    need to override this method
    @Override
    public int getItemViewType(int position) {
        if(isPositionHeader(position))
            return TYPE_HEADER;
        return TYPE_ITEM;
    }

    private boolean isPositionHeader(int position)
    {
        return position == 0;
    }

//increasing getItemcount to 1. This will be the row of header.
    @Override
    public int getItemCount() {
        return listItems.size()+1;
    }

    class VHHeader extends RecyclerView.ViewHolder{
        TextView txtTitle;
        public VHHeader(View itemView) {
            super(itemView);
            this.txtTitle = (TextView)itemView.findViewById(R.id.txtHeader);
        }
    }

    class VHItem extends RecyclerView.ViewHolder{
        TextView txtName;
        ImageView iv;
        public VHItem(View itemView) {
            super(itemView);
            this.txtName = (TextView)itemView.findViewById(R.id.txtName);
            this.iv = (ImageView)itemView.findViewById(R.id.ivListItem);
        }
    }
}

 

 

6. Main Activity

In this class I have already created dummy data to use for our RecyclerView. Now all we need to do to complete this job is make an instance of Adapter and pass it to our RecyclerView and see what we will get.

 

Main Activity Class

public class MainActivity extends AppCompatActivity {

   RecyclerView recyclerView;
   LinearLayoutManager linearLayoutManager;
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       recyclerView = (RecyclerView)findViewById(R.id.my_recycler_view);
       linearLayoutManager = new LinearLayoutManager(this);
       MyRecyclerAdapter adapter = new MyRecyclerAdapter(getHeader(),     getListItems());
       recyclerView.setLayoutManager(linearLayoutManager);
       recyclerView.setAdapter(adapter);
   }

   public  Header getHeader()
   {
       Header header = new Header();
       header.setHeader("I'm header");
       return header;
   }

   public  List<ListItem> getListItems()
   {
       List<ListItem> listItems = new ArrayList<ListItem>();
       for (int i = 0; i<10; i++) {
           ListItem item = new ListItem();
           item.setName("image" + i);
           if (i % 2 == 0)
               item.setId(R.drawable.sweetlife);
           else
               item.setId(R.drawable.young);
           listItems.add(item);
       }
       return listItems;
   }
}

 

7. Output

Tutorial How To Add Header to RecyclerView in Android

 

Conclusion

Here we have a post related to how to Add Header to RecyclerView. I didn’t show footers specifically in this post because the same principles apply.  Hope you find this post useful.

The completed project can be downloaded here.

 

 

If you like our articles, please follow and like our Facebook page where we regularly share interesting posts  and check out our other blog articles.

RobustTechHouse is a leading tech company focusing on mobile app development in Singapore. If you are interested to engage RobustTechHouse for your projects, you can contact us here.

Recommended Posts
  • Priyanka

    have been searching for a solution from long, this is the only clean and effective of adding headers in recycler view.. Thanks a lot!

  • Parth Vora

    Its not working in android studio 2.1.1 please help!!!

  • Noble Eldhose

    Hai do you ahve any idea about how can we add view pager
    as recycler header

  • Sara Peña

    What to change to implement a footer?

  • Pranjal Choladhara

    First item is not visible… Check my code

    import android.content.Context;
    import android.os.Bundle;
    import android.support.v4.app.Fragment;
    import android.support.v4.app.FragmentActivity;
    import android.support.v4.app.FragmentManager;
    import android.support.v4.app.FragmentTransaction;
    import android.support.v7.widget.RecyclerView;
    import android.util.Log;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ImageView;
    import android.widget.TextView;
    import android.widget.Toast;

    import com.amulyakhare.textdrawable.TextDrawable;
    import com.amulyakhare.textdrawable.util.ColorGenerator;

    import java.util.ArrayList;

    import in.nxtgym.R;
    import in.nxtgym.emp.ui.Training_Schedule_List;
    import in.nxtgym.emp_detail.ui.Clients;
    import in.nxtgym.member_detail.ui.MemberMaster;
    import in.nxtgym.models.SimpleListModel;

    public class Adptr_SimpleListItem extends RecyclerView.Adapter {
    Context context;
    ArrayList list;
    LayoutInflater inflater;
    private ColorGenerator mColorGenerator = ColorGenerator.MATERIAL;
    private TextDrawable.IBuilder mDrawableBuilder;

    private static final int TYPE_HEADER = 0;
    private static final int TYPE_ITEM = 1;

    public Adptr_SimpleListItem(Context context, ArrayList list){
    this.context = context;
    this.list = list;
    this.inflater = LayoutInflater.from(context);
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    if(viewType==TYPE_ITEM) {
    View view = inflater.inflate(R.layout.simple_list_item, parent, false);
    return new ItemsView(view);
    }
    else {
    View view = inflater.inflate(R.layout.simple_list_header, parent, false);
    return new Header(view);
    }
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    if(holder instanceof Header){
    Header header = (Header) holder;
    header.head.setText(“List of Personal Trainers”);
    header.subhead.setVisibility(View.GONE);
    }
    if(holder instanceof ItemsView) {
    ItemsView itemsView = (ItemsView) holder;
    SimpleListModel items = list.get(position);
    mDrawableBuilder = TextDrawable.builder()
    .beginConfig()
    .withBorder(0)
    .endConfig()
    .round();
    TextDrawable drawable = mDrawableBuilder.build(String.valueOf(items.getHeadline().charAt(0)), mColorGenerator.getColor(items.getHeadline()));
    itemsView.image.setImageDrawable(drawable);
    itemsView.L_id.setText(“” + items.getID());
    itemsView.L_Headline.setText(items.getHeadline());
    itemsView.L_Subhead.setText(items.getSubHead());
    }
    }

    public int getItemViewType(int position) {
    if(position==0){return TYPE_HEADER;}
    return TYPE_ITEM;
    }
    @Override
    public int getItemCount() {
    return list.size();
    }

    class Header extends RecyclerView.ViewHolder{
    TextView head;
    TextView subhead;
    public Header(View itemView) {
    super(itemView);
    head = (TextView) itemView.findViewById(R.id.headline);
    subhead = (TextView) itemView.findViewById(R.id.sub_headline);
    }
    }

    class ItemsView extends RecyclerView.ViewHolder implements View.OnClickListener{
    ImageView image;
    TextView L_id;
    TextView L_Headline;
    TextView L_Subhead;

    public ItemsView(View itemView) {
    super(itemView);
    image = (ImageView) itemView.findViewById(R.id.list_image);
    L_id = (TextView) itemView.findViewById(R.id.list_item_id);
    L_Headline = (TextView) itemView.findViewById(R.id.list_item_1);
    L_Subhead = (TextView) itemView.findViewById(R.id.list_item_2);
    itemView.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
    int pos = getAdapterPosition();
    long MemberId = list.get(pos).getID();

    Fragment fragment = new Clients();
    Bundle bundle = new Bundle();
    bundle.putLong(“EMP_ID”, MemberId);
    fragment.setArguments(bundle);

    FragmentManager fm = ((FragmentActivity)context).getSupportFragmentManager();
    FragmentTransaction transaction = fm.beginTransaction();
    transaction.replace(R.id.frame_container, fragment, “MEMBER_MASTER”);
    transaction.addToBackStack(“A_MEMBER_MASTER”);
    transaction.commit();

    }
    }

    }

    • Paulo Miranda

      I had the same problem. I did not increase

      //increasing getItemcount to 1. This will be the row of header.

      @Override

      public int getItemCount() {

      return listItems.size()+1; < —— HERE

      }

      AND

      ListItem currentItem = getItem(position-1); < —- decrease

  • Michael David McKenna

    Perfect!!

  • Michel Marin

    Very nicely done. If I have 6 columns of different widths and different types will all 6 headers be aligned with the data rows? Thank you

Contact Us

We look forward to your messages. Please drop us a note for any enquiries and we'll get back to you, asap.

Not readable? Change text. captcha txt
Blogging For ECommerceecommerce5