Android RecyclerView Section Header Example | Group By Header

android recyclerview section header, android image slider from url, android multi column listview, android recyclerview multi column

Android RecyclerView Section Header Example is the hot topic of today.

We will create a recyclerview which has specific headers among it’s various child items.

Last Output

Section Header

Section header is a particular row item which can categorized recyclerview’s child items.

For example, you are making recyclerview with vehicle’s manufacturer company names.

Here, you can categorize company names with categories like Cars, Bikes, Air crafts etc.

In the first row you will write “Cars” and in the second and third row, you may write “Mercedes” and “Audee“.

In the fourth row you give section header named “Bikes” and you put “Honda” and “Ducati” in Fifth and sixth row of recyclerview. This process continues til the end.

In this example, we will create a recyclerview where all the section header have different layout structure than the normal child row items.

Read to make section header in Listview.

Let us go through all the steps.

Step 1. Build.gradle(Module: app)

We have to add gradle lines to import the required classes of recyclerview and cardview.

Write following in the build.gradle(Module: app) file

implementation 'com.android.support:recyclerview-v7:27.1.1'
implementation 'com.android.support:cardview-v7:27.1.1'

Step 2. Drawable files

Create a drawable resource file named cardview.xml under res->drawable directory

Copy the following code in cardview.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_focused="true">
        <shape android:shape="rectangle">
            <padding
                android:left="4dp"
                android:top="4dp"
                android:right="4dp"
                android:bottom="4dp"
                />
            <gradient android:startColor="#1cb73b" android:endColor="#29ba48" android:angle="270" />

            <corners android:topLeftRadius="4dp" android:topRightRadius="4dp"/>
        </shape>
    </item>

    <item android:state_focused="false"
        >
        <shape android:shape="rectangle">
            <padding
                android:left="4dp"
                android:top="4dp"
                android:right="4dp"
                android:bottom="4dp"
                />

            <gradient android:startColor="#1cb724" android:endColor="#29ba41" android:angle="270" />

            <corners android:topLeftRadius="4dp" android:topRightRadius="4dp" />
        </shape>
    </item>

</selector>

Above file will create specific background for the section header row.

I have given gradient effect with green color shadows in this file.

Make another file named cardview_child.xml and add following code

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_focused="true">
        <shape android:shape="rectangle">
            <padding
                android:left="4dp"
                android:top="4dp"
                android:right="4dp"
                android:bottom="4dp"
                />
            <gradient android:startColor="#901cb7" android:endColor="#8529ba" android:angle="270" />

            <corners android:topLeftRadius="4dp" android:topRightRadius="4dp"/>
        </shape>
    </item>

    <item android:state_focused="false"
        >
        <shape android:shape="rectangle">
            <padding
                android:left="4dp"
                android:top="4dp"
                android:right="4dp"
                android:bottom="4dp"
                />

            <gradient android:startColor="#8832c1" android:endColor="#8541c4" android:angle="270" />

            <corners android:topLeftRadius="4dp" android:topRightRadius="4dp" />
        </shape>
    </item>

</selector>
  • cardview_child.xml file will create the particular background for child rows of recyclerview.

In this file, purple color gradients will make child row more colorful.

Step 3. RecyclerView Row resources

Now we need to create two layout resources file. One for header row and one for child row.

Make a new layout resource file and name it “rv_header.xml” and add the below source code

<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="wrap_content"
    tools:context=".MainActivity">

    <android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
        android:id="@+id/card_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:layout_marginBottom="10dp"
        card_view:cardCornerRadius="4dp">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/tv"
                android:height="50dp"
                android:background="@drawable/cardview"
                android:gravity="center_vertical"
                android:paddingLeft="10dp"
                android:text="Header : Vehicle Type"
                android:textColor="#fff"
                android:textStyle="bold"
                android:textSize="30sp" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/tvHeader"
                android:background="#ece4e4"
                android:text="Bike"
                android:padding="10dp"
                android:textColor="#000"
                android:textSize="25sp"/>


        </LinearLayout>

    </android.support.v7.widget.CardView>
</RelativeLayout>

This “rv_header.xml” file will create a layout structure for header file.

Now create another layout resource file named “rv_child.xml”. Following code is for this file.

<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="wrap_content"
    tools:context=".MainActivity">

    <android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
        android:id="@+id/card_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:layout_marginBottom="10dp"
        card_view:cardCornerRadius="4dp">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/tv"
                android:height="50dp"
                android:background="@drawable/cardview_child"
                android:gravity="center_vertical"
                android:paddingLeft="10dp"
                android:text="Sub Item"
                android:textColor="#fff"
                android:textStyle="bold"
                android:textSize="30sp" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/tvChild"
                android:background="#71b9d6"
                android:text="Bike"
                android:padding="10dp"
                android:textColor="#a72b2b"
                android:textSize="25sp"/>


        </LinearLayout>

    </android.support.v7.widget.CardView>
</RelativeLayout>

Every child row will use the above code to create it’s layout structure.

Step 4. Model Classes

Create a new class named HeaderModel.java

Add the below source code in it

package com.example.parsaniahardik.recyclerview_section_header;

public class HeaderModel implements MainActivity.ListItem{

    String header;

    public void setheader(String header) {
        this.header = header;
    }

    @Override
    public boolean isHeader() {
        return true;
    }

    @Override
    public String getName() {
        return header;
    }
}

This class contains necessary methods regarding headers of the recyclerview.

In the above code, isHeader() and getName() methods are override because this class implements the ListItem interface which is written in the Main Activity.

isHeader() method returns the boolean value. If the the object is of the HeaderModel class, then it will return true otherwise false.

getName() method will return the name of the string whether it is vehicle type or manufacturer, it does not matter here.

(You will see the use of these two above methods in the adapter class later in this tutorial)

setHeader() method is used to set the name of the header.

Now create a new class and give it a name “ChildModel.java”

Put following code in it

public class ChildModel implements MainActivity.ListItem{

    String child;

    public void setChild(String child) {
        this.child = child;
    }

    @Override
    public boolean isHeader() {
        return false;
    }

    @Override
    public String getName() {
        return child;
    }
}

All three methods present in the above class are similar with the methods of HeaderModel class.

The text which is set and get by various methods are of the child rows name, while in HeaderModel class, the text was about header name.

Step 5. Writing Main Activity

You need to change the Main activity’s code now.

Add below code in activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#9e9191"
    tools:context=".MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="15dp"/>

</LinearLayout>

I have taken recyclerview in the main layout.

Write down the following source code into MainActivity.java class

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    private RecyclerView recyclerView;
    private CustomAdapter customAdapter;

    private String[] vehicleTypes = new String[]{"Cars", "Bikes",
            "Air Crafts","Old Vehicles"};

    private ArrayList<ListItem> listItemArrayList;

    private String[] childnames = new String[]{"Range Rover", "Lamborghini",
            "Rolls Royce","Ferrari","Harley davidson","Ducati","BMW","Honda","Boeing","Airbus","Royal Air","Space X","Horse","Elephant","Camel","Donkey"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        recyclerView = (RecyclerView) findViewById(R.id.recycler);

        listItemArrayList = new ArrayList<>();
        populateList();

        customAdapter = new CustomAdapter(this,listItemArrayList);
        recyclerView.setAdapter(customAdapter);
        recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext(), LinearLayoutManager.VERTICAL, false));
    }

    public interface ListItem {
        boolean isHeader();
        String getName();
    }

    private void populateList(){

        int headerdone = 0, childdone = 0;

        for(int i = 0; i < 20; i++){

            if(i == 0 || i == 5 | i == 10 | i == 15){
                HeaderModel vehicleModel = new HeaderModel();
                vehicleModel.setheader(vehicleTypes[headerdone]);
                listItemArrayList.add(vehicleModel);
                headerdone = headerdone + 1;
            }else {
                ChildModel childModel = new ChildModel();
                childModel.setChild(childnames[childdone]);
                listItemArrayList.add(childModel);
                childdone = childdone + 1;
            }
        }

    }
}

Understanding above code

Read the below lines

 private String[] vehicleTypes = new String[]{"Cars", "Bikes",
            "Air Crafts","Old Vehicles"};
 private String[] childnames = new String[]{"Range Rover", "Lamborghini",
            "Rolls Royce","Ferrari","Harley davidson","Ducati","BMW","Honda","Boeing","Airbus","Royal Air","Space X","Horse","Elephant","Camel","Donkey"};

There are two string array variables are there.

First string array variable called vehicleTypes represents the types of the vehicles. These vehicle types are the headers of the recyclerview.

Second string array variable called childnames contains the names of the vehicle manufacture companies. These names are the child rows of the recyclerview.

Interface

HeaderModel.java and ChildModel.java were implementing the ListItem interface. This interface is defined here in the Main Activity.

Following is it’s coding lines

  public interface ListItem {
        boolean isHeader();
        String getName();
    }

It contains two methods so both HeaderModel.java and ChildModel.java classes were overriding these methods.

Populating RecyclerView Data

Our data for header and child rows are present in the two strings variables as we have just shown above.

Now we need to convert this data in the arraylist of interface objects to pass them into the adapter class.

Following method will do this for us

 private void populateList(){

        int headerdone = 0, childdone = 0;

        for(int i = 0; i < 20; i++){

            if(i == 0 || i == 5 | i == 10 | i == 15){
                HeaderModel vehicleModel = new HeaderModel();
                vehicleModel.setheader(vehicleTypes[headerdone]);
                listItemArrayList.add(vehicleModel);
                headerdone = headerdone + 1;
            }else {
                ChildModel childModel = new ChildModel();
                childModel.setChild(childnames[childdone]);
                listItemArrayList.add(childModel);
                childdone = childdone + 1;
            }
        }

    }

In the RecyclerView, first row will represent the Header name. Then next four rows will be child rows.

As per this calculations, First, Sixth, eleventh and sixteenth rows of the recyclerview will be the header.

So in the above code, if condition will be true for First, Sixth, eleventh and sixteenth iterations of the for loop.

When the if condition is true, an object of the HeaderModel class is created, populated with the name and then it is inserted into the arraylist of interface (which is listItemArrayList).

When the if condition is false, an object of the ChildModel class is created, populated with name and then it is inserted in the arraylist of interface (which is listItemArrayList).

After the successful call of the populateList() method, listItemArrayList passed into the constructor of the Adapter class using below lines

customAdapter = new CustomAdapter(this,listItemArrayList);

Step 6. Custom Adapter

Now finally, we are at the adapter class to fill the recyclerview.

Create a new class named CustomAdapter.java

Add the below code in it

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.ArrayList;

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

    private static final int LAYOUT_HEADER= 0;
    private static final int LAYOUT_CHILD= 1;

    private LayoutInflater inflater;
    private Context context;
    private ArrayList<MainActivity.ListItem> listItemArrayList;

    public CustomAdapter(Context context,ArrayList<MainActivity.ListItem> listItemArrayList){

        inflater = LayoutInflater.from(context);
        this.context = context;
        this.listItemArrayList = listItemArrayList;
    }

    @Override
    public int getItemCount() {
        return listItemArrayList.size();
    }

    @Override
    public int getItemViewType(int position)
    {
        if(listItemArrayList.get(position).isHeader()) {
            return LAYOUT_HEADER;
        }else
            return LAYOUT_CHILD;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        RecyclerView.ViewHolder holder;
        if(viewType==LAYOUT_HEADER){
            View view = inflater.inflate(R.layout.rv_header, parent, false);
            holder = new MyViewHolderHeader(view);
        }else {
            View view = inflater.inflate(R.layout.rv_child, parent, false);
             holder = new MyViewHolderChild(view);
        }


        return holder;
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {

        if(holder.getItemViewType()== LAYOUT_HEADER)
        {
            MyViewHolderHeader vaultItemHolder = (MyViewHolderHeader) holder;
            vaultItemHolder.tvHeader.setText(listItemArrayList.get(position).getName());
        }
        else {

            MyViewHolderChild vaultItemHolder = (MyViewHolderChild) holder;
            vaultItemHolder.tvchild.setText(listItemArrayList.get(position).getName());

        }

    }


    class MyViewHolderHeader extends RecyclerView.ViewHolder{

        TextView tvHeader;

        public MyViewHolderHeader(View itemView) {
            super(itemView);

            tvHeader = (TextView) itemView.findViewById(R.id.tvHeader);
         }

    }

    class MyViewHolderChild extends RecyclerView.ViewHolder{

        TextView tvchild;

        public MyViewHolderChild(View itemView) {
            super(itemView);

            tvchild = (TextView) itemView.findViewById(R.id.tvChild);
        }

    }

}

Explanation

Read the below code

  @Override
    public int getItemViewType(int position)
    {
        if(listItemArrayList.get(position).isHeader()) {
            return LAYOUT_HEADER;
        }else
            return LAYOUT_CHILD;
    }

We are deciding whether the view of the row should be header view or child view in the above method.

We are using isHeader() method for this purpose.

LAYOUT_HEADER and LAYOUT_CHILD are the integer constants.

Consider below codes of classes

class MyViewHolderHeader extends RecyclerView.ViewHolder{

        TextView tvHeader;

        public MyViewHolderHeader(View itemView) {
            super(itemView);

            tvHeader = (TextView) itemView.findViewById(R.id.tvHeader);
         }

    }

    class MyViewHolderChild extends RecyclerView.ViewHolder{

        TextView tvchild;

        public MyViewHolderChild(View itemView) {
            super(itemView);

            tvchild = (TextView) itemView.findViewById(R.id.tvChild);
        }

    }

Two classes are defined in the above code.

First one represents the Header and second one is for Child row.

We are just declaring the textviews for header and child row in the above classes.

Now consider the following code

 @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {

        if(holder.getItemViewType()== LAYOUT_HEADER)
        {
            MyViewHolderHeader vaultItemHolder = (MyViewHolderHeader) holder;
            vaultItemHolder.tvHeader.setText(listItemArrayList.get(position).getName());
        }
        else {

            MyViewHolderChild vaultItemHolder = (MyViewHolderChild) holder;
            vaultItemHolder.tvchild.setText(listItemArrayList.get(position).getName());

        }

    }

We will set the textview value in onBingViewHolder method.

Here I have checked one if condition. When the if condition is true, textview(tvHeader) which defined in the MyViewHolderHeader class will get the value.

When the if condition is false, textview(tvchild) which defined in the MyViewHolderChild class will get the value.

Also Read,

Download the source code for android recyclerview section header

[sociallocker]Download RecyclerView Section Header Code[/sociallocker]