Android

How to add Header to RecyclerView in Android

Pinterest LinkedIn Tumblr

RecyclerView is flexible and advance version of GridView and ListView. It uses less memory for listing the large amount of datasets and collections. In this turorial, we will look at how to create a listing with multiple headers in RecyclerView.

This is the fifth in a RecyclerView Series which covers the fundamentals of RecyclerView. If you already have a solid understanding of how to create a RecyclerView, carry on. Otherwise consider starting with this.

Jump to section

Demo

https://www.youtube.com/watch?v=0AOiDhP_fzo&ab_channel=ProCodeGuru
RecyclerView with Multiple Headers Demo

Step-1 (Create a new project)

Create a new project and select the blank template

Step-2 (Add dependencies)

Go to the build.gradle.xml file and add the below code.

    implementation 'androidx.appcompat:appcompat:1.3.1'
    implementation 'com.google.android.material:material:1.4.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'

Step-3 (Project Resources)

Open the colors.xml file and replace it with the below code

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="purple_200">#FFBB86FC</color>
    <color name="purple_500">#FF6200EE</color>
    <color name="purple_700">#FF3700B3</color>
    <color name="teal_200">#FF03DAC5</color>
    <color name="teal_700">#FF018786</color>
    <color name="black">#FF000000</color>
    <color name="white">#FFFFFFFF</color>

    <!-- App Colors -->
    <color name="color_bg_card">#343434</color>
    <color name="color_bg">#292929</color>
    <color name="color_red">#FF0B0B</color>
    <color name="color_header">#F56E0B</color>
</resources>

Go to the strings.xml file and add the below code.

<resources>
    <string name="app_name">RecyclerViewListingWithHeaderExample</string>
    <string name="demo_title">RecyclerView Listing with Header Example</string>
    <string name="discount">25% Off</string>
    <string name="available_in_stock">Available in stock</string>
    <string name="men_collection">Men Collection</string>
    <string name="women_collection">Women Collection</string>
    <string name="children_collection">Children Collection</string>

    <!--Category Watches-->
    <string name="cat_watch_one">Omega</string>
    <string name="cat_watch_two">Rolex</string>
    <string-array name="arr_men_watches">
        <item>@string/cat_watch_one</item>
        <item>@string/cat_watch_two</item>
    </string-array>


    <!--Category Shoes-->
    <string name="cat_shoe_one">Adilette Slides</string>
    <string name="cat_shoe_two">OG Old Skool LX</string>
    <string-array name="arr_men_shoes">
        <item>@string/cat_shoe_one</item>
        <item>@string/cat_shoe_two</item>
    </string-array>
</resources>

Step-4 (Design the header layout)

Create a layout file that defines what the header looks like. Navigate to the app > res > layout > Right-click on it> New > Layout Resource File called adapter_header.xml. Add the below code

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <TextView
        android:id="@+id/tvTitle"
        android:text="@string/men_collection"
        android:textSize="22sp"
        android:textStyle="bold"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_margin="10dp"
        android:textColor="@color/color_header"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</androidx.constraintlayout.widget.ConstraintLayout>

Step-5 (Design the RecyclerView row layout)

Create a layout file that defines what the RecyclerView row looks like. Navigate to the app > res > layout > Right-click on it> New > Layout Resource File called adapter_listing.xml. Add the below code

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    app:cardBackgroundColor="@color/color_bg_card"
    app:cardUseCompatPadding="true"
    app:cardCornerRadius="5dp"
    android:layout_height="120dp">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:padding="10dp"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/tvTitle"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:text="@string/cat_shoe_one"
            android:textColor="@color/white"
            android:lines="2"
            android:ellipsize="end"
            android:textSize="18sp"
            android:layout_marginEnd="5dp"
            app:layout_constraintEnd_toStartOf="@+id/tvDiscount"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/tvDiscount"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/discount"
            android:textColor="@color/white"
            android:textSize="16sp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/tvStockAvailability"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/available_in_stock"
            android:textSize="16sp"
            android:textColor="@color/color_red"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintBottom_toBottomOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>

Step-6 (Working with Modal class)

We will create two Java files, one for the header and the second for the listing data. Create a Java file, which will have the header type and title of the header and renamed it with HeaderM.java. Add the below code

package com.example.recyclerviewlistingwithheaderexample;

public class HeaderM {
    private String headerTitle;
    private int headerType; // 1 for the header title and 2 for the list item.

    public HeaderM(String headerTitle, int headerType) {
        this.headerTitle = headerTitle;
        this.headerType = headerType;
    }

    public String getHeaderTitle() {
        return headerTitle;
    }

    public void setHeaderTitle(String headerTitle) {
        this.headerTitle = headerTitle;
    }

    public int getHeaderType() {
        return headerType;
    }

    public void setHeaderType(int headerType) {
        this.headerType = headerType;
    }
}

Create a new Java file called ListItemM.java. Add the below code

package com.example.recyclerviewlistingwithheaderexample;

public class ListItemM extends HeaderM{
    private String title; // title of the item
    private String discount; // discounted price of the item
    private boolean isInStock; // bool will check item is in stock or not

    public ListItemM(String headerTitle, int HeaderType, String title, String discount, boolean isInStock) {
        super(headerTitle,HeaderType);
        this.title = title;
        this.discount = discount;
        this.isInStock = isInStock;
    }
    public ListItemM(String headerTitle, int HeaderType){
        super(headerTitle,HeaderType);
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getDiscount() {
        return discount;
    }

    public void setDiscount(String discount) {
        this.discount = discount;
    }

    public boolean isInStock() {
        return isInStock;
    }

    public void setInStock(boolean inStock) {
        isInStock = inStock;
    }
}

Step-7 (Create RecyclerView Adapter)

Create a new Java file and renamed it AdapterListing.java. In the onCreateViewHolder() method, we will return two layout views according to the current view type. onBindViewHolder() will hold the data according to view type and will display it to the current view holder. getItemViewType() returns the type of current rendering row. Add the below code

package com.example.recyclerviewlistingwithheaderexample;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import java.util.List;

public class AdapterListing extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private List<ListItemM> listItemMList;
    private Context _context;


    AdapterListing(List<ListItemM> listItemMList) {
        this.listItemMList = listItemMList;
    }


    /**
     * Listing View Holder which holds the view of listing layout during rendering
     */
    private class ListItemViewHolder extends RecyclerView.ViewHolder {
        private TextView tvTitle;
        private TextView tvDiscount;

        public ListItemViewHolder(View itemView) {
            super(itemView);
            tvTitle = itemView.findViewById(R.id.tvTitle);
            tvDiscount = itemView.findViewById(R.id.tvDiscount);
        }
    }

    /**
     * Header View Holder which holds the view of header layout during rendering
     */
    private class HeaderViewHolder extends RecyclerView.ViewHolder {
        private TextView tvTitle;

        public HeaderViewHolder(View itemView) {
            super(itemView);
            tvTitle = itemView.findViewById(R.id.tvTitle);
        }
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        _context = parent.getContext();
        if (viewType == MainActivity.TYPE_HEADER) { // return the header layout if current rendering view type of row is 1
            View v1 = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_header, parent, false);
            return new HeaderViewHolder(v1);
        } else if (viewType == MainActivity.TYPE_LISTING) { // return the listing layout if current rendering view type of row is 2
            View v1 = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_listing, parent, false);
            return new ListItemViewHolder(v1);
        }

        return null;
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        if (holder.getItemViewType() == MainActivity.TYPE_HEADER) { // if rendering row is header then get the HeaderM modal
            HeaderM headerM = listItemMList.get(position);
            HeaderViewHolder headerViewHolder = (HeaderViewHolder) holder;
            headerViewHolder.tvTitle.setText(headerM.getHeaderTitle());
        } else if (holder.getItemViewType() == MainActivity.TYPE_LISTING) { // if the rendering row is listing the get the ListItemM modal
            ListItemViewHolder listItemViewHolder = (ListItemViewHolder) holder;
            ListItemM listItemM = listItemMList.get(position);
            listItemViewHolder.tvTitle.setText(listItemM.getTitle());
            listItemViewHolder.tvDiscount.setText(listItemM.getDiscount());
        }
    }

    @Override
    public int getItemCount() {
        // return the size of the list
        return listItemMList.size();
    }

    @Override
    public int getItemViewType(int position) {
        // return the current row type
        return listItemMList.get(position).getHeaderType();
    }
}

Step-8 (activity_main.xml file)

Go to the activity_main.xml file and add the below code.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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="@color/color_bg"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/tvDemoTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:gravity="center"
        android:text="@string/demo_title"
        android:textColor="@color/white"
        android:textSize="22sp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rcvListing"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_margin="10dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tvDemoTitle" />

</androidx.constraintlayout.widget.ConstraintLayout>

Step-9 (MainActivity.java)

Go to the MainActivity.java file and add the below code. Comments are added inside the code for understanding the code. If you get confuse post the comment below.

package com.example.recyclerviewlistingwithheaderexample;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.os.Bundle;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private RecyclerView rcvListing;
    private AdapterListing adapterListing;
    private List<ListItemM> listItemMList;
    public final static int TYPE_HEADER = 1;
    public final static int TYPE_LISTING = 2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initComponents();
        prepareMenCollection();
        prepareWomenCollection();
        prepareChildrenCollection();
        adapterListing.notifyDataSetChanged();
    }

    /**
     * initialize the components
     */
    private void initComponents() {
        listItemMList = new ArrayList<>();
        adapterListing = new AdapterListing(listItemMList);
        rcvListing = findViewById(R.id.rcvListing);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        linearLayoutManager.setOrientation(RecyclerView.VERTICAL);
        rcvListing.setLayoutManager(linearLayoutManager);
        rcvListing.setAdapter(adapterListing);
    }

    /**
     * prepare the Men collection listing with header
     */
    private void prepareMenCollection() {
        // header
        ListItemM listItemM = new ListItemM(getString(R.string.men_collection), TYPE_HEADER);
        listItemMList.add(listItemM);

        // body
        String[] menShoeCollectionArr = getResources().getStringArray(R.array.arr_men_shoes);
        for (String shoe : menShoeCollectionArr) {
            ListItemM item = new ListItemM(getString(R.string.men_collection), TYPE_LISTING, shoe, getString(R.string.discount), true);
            listItemMList.add(item);
        }

        String[] menWatchCollectionArr = getResources().getStringArray(R.array.arr_men_shoes);
        for (String watch : menWatchCollectionArr) {
            ListItemM item = new ListItemM(getString(R.string.men_collection), TYPE_LISTING, watch, getString(R.string.discount), true);
            listItemMList.add(item);
        }
    }

    /**
     * prepare the Women collection listing with header
     */
    private void prepareWomenCollection() {
        // header
        ListItemM listItemM = new ListItemM(getString(R.string.women_collection), TYPE_HEADER);
        listItemMList.add(listItemM);

        // body
        String[] menShoeCollectionArr = getResources().getStringArray(R.array.arr_men_shoes);
        for (String shoe : menShoeCollectionArr) {
            ListItemM item = new ListItemM(getString(R.string.men_collection), TYPE_LISTING, shoe, getString(R.string.discount), true);
            listItemMList.add(item);
        }

        String[] menWatchCollectionArr = getResources().getStringArray(R.array.arr_men_shoes);
        for (String watch : menWatchCollectionArr) {
            ListItemM item = new ListItemM(getString(R.string.men_collection), TYPE_LISTING, watch, getString(R.string.discount), true);
            listItemMList.add(item);
        }
    }

    /**
     * prepare the Children collection listing with header
     */
    private void prepareChildrenCollection() {
        // header
        ListItemM listItemM = new ListItemM(getString(R.string.children_collection), TYPE_HEADER);
        listItemMList.add(listItemM);

        // body
        String[] menShoeCollectionArr = getResources().getStringArray(R.array.arr_men_shoes);
        for (String shoe : menShoeCollectionArr) {
            ListItemM item = new ListItemM(getString(R.string.men_collection), TYPE_LISTING, shoe, getString(R.string.discount), true);
            listItemMList.add(item);
        }

        String[] menWatchCollectionArr = getResources().getStringArray(R.array.arr_men_shoes);
        for (String watch : menWatchCollectionArr) {
            ListItemM item = new ListItemM(getString(R.string.men_collection), TYPE_LISTING, watch, getString(R.string.discount), true);
            listItemMList.add(item);
        }
    }

}

Step-10 (Download Project Resources)

Thanks for reading the tutorial. Subscribe to my YouTube channel. Like and Share my Facebook page with your friends.

Write A Comment