Android RecyclerView Sticky Header Like iphone | Pinned Header

android listview sticky header like iphone, android recyclerview sticky header like iphone, android listview with header and footer, android recyclerview with header and footer

Welcome to Android RecyclerView Sticky Header Like iphone Example.

We are going to develop a recyclerview with pinned headers in this tutorial.

You may have watched this concept of sticky or pinned header in iphone or ios.

Sticky header will stick at the top side of the recyclerview.

Now header can be one or more depending upon the type of the children items of recyclerview.

If there are more than one header, than header will be replace by another header when user scroll up all the items of the old header.

Android’s built in system do not provide any direct method or class to develop this kind of recyclerview.

So we need to use external github library in this example tutorial.

View RecyclerView

Step 1. Fetching Dependency

We will use one github library in this tutorial.

It will allow us to use some classes which are required in this example.

For this, add the below line in build.gradle(Modile:app) file

 implementation 'com.shuhart.stickyheader:stickyheader:1.0.5'
 implementation 'com.android.support:recyclerview-v7:27.1.1'

First line will integrate third party library.

Other one will fetch the required classes to use RecyclerView.

Step 2. Layout For Header And Children

In this example, we need to create two different layout XML files.

One will represent the header and another will represent children items.

Create a new file in res->layout directory and give it a name recycler_view_header_item.xml

Add the below code in recycler_view_header_item.xml file

<?xml version="1.0" encoding="utf-8"?>
<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="?listPreferredItemHeight">

    <TextView
        android:id="@+id/text_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/darker_gray"
        android:gravity="center_vertical"
        android:paddingLeft="16dp"
        android:paddingRight="16dp"
        android:textColor="@android:color/black"
        android:textSize="16sp"
        tools:text="Header" />
</RelativeLayout>
  • Just one textview in the above file. You can also add imageview and other widget as per your requirements.

Make another XML file named recycler_view_item.xml and copy the following in it

<?xml version="1.0" encoding="utf-8"?>
<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="?listPreferredItemHeight">

    <TextView
        android:id="@+id/text_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/white"
        android:gravity="center_vertical"
        android:paddingLeft="16dp"
        android:paddingRight="16dp"
        android:textColor="@android:color/black"
        android:textSize="16sp"
        tools:text="Item" />
</RelativeLayout>

Step 3. New Interface

Create a new Interface and give it a name Section.java

Code structure for interface Section.java is as below

public interface Section {

    boolean isHeader();
    String getName();

    int sectionPosition();
}

We will use this interface to create an arraylist with the objects of two different model classes.

Step 4. Models For Header And Child

Prepare a new JAVA class and name it as ChildModel.java

Write down the following coding lines in ChildModel.java

public class ChildModel implements Section {

    String child;
    private int section;

    public ChildModel(int section) {
        this.section = section;
    }

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

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

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

    @Override
    public int sectionPosition() {
        return section;
    }
}

Now make another class named HeaderModel.java and code for it is as below

public class HeaderModel implements Section {

    String header;
    private int section;

    public HeaderModel(int section) {
        this.section = section;
    }

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

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

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

    @Override
    public int sectionPosition() {
        return section;
    }
}

These model classes are useful for the maintenance of data while populating the RecyclerView.

Models are implementing Section interface and thus it also overrides all the methods of that interface.

Step 5. Section Adapter

Now it is time to write an adapter class for recyclerview.

Make a new class named SectionAdapter.java and write the following lines

import android.annotation.SuppressLint;
import android.content.Context;
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.TextView;
import com.shuhart.stickyheader.StickyAdapter;
import java.util.ArrayList;

public class SectionAdapter extends StickyAdapter<RecyclerView.ViewHolder, RecyclerView.ViewHolder> {

    private ArrayList<Section> sectionArrayList;
    private static final int LAYOUT_HEADER= 0;
    private static final int LAYOUT_CHILD= 1;

    public SectionAdapter(Context context, ArrayList<Section> sectionArrayList){

       // inflater = LayoutInflater.from(context);
       // this.context = context;
        this.sectionArrayList = sectionArrayList;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());

        if (viewType == LAYOUT_HEADER ) {
            return new HeaderViewholder(inflater.inflate(R.layout.recycler_view_header_item, parent, false));
        }else {
            return new ItemViewHolder(inflater.inflate(R.layout.recycler_view_item, parent, false));
        }
    }

    @SuppressLint("SetTextI18n")
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

        if (sectionArrayList.get(position).isHeader()) {
            ((HeaderViewholder) holder).textView.setText( sectionArrayList.get(position).getName());
        } else {
            ((ItemViewHolder) holder).textView.setText(sectionArrayList.get(position).getName());
        }
    }

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

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

    @Override
    public int getHeaderPositionForItem(int itemPosition) {
        Log.d("seeee",""+itemPosition+"......"+sectionArrayList.get(itemPosition).sectionPosition());
        return sectionArrayList.get(itemPosition).sectionPosition();
    }

    @SuppressLint("SetTextI18n")
    @Override
    public void onBindHeaderViewHolder(RecyclerView.ViewHolder holder, int headerPosition) {
        ((HeaderViewholder) holder).textView.setText( sectionArrayList.get(headerPosition).getName());
    }

    @Override
    public RecyclerView.ViewHolder onCreateHeaderViewHolder(ViewGroup parent) {
        return createViewHolder(parent, LAYOUT_HEADER);
    }

    public static class HeaderViewholder extends RecyclerView.ViewHolder {
        TextView textView;

        HeaderViewholder(View itemView) {
            super(itemView);
            textView = itemView.findViewById(R.id.text_view);
        }
    }

    public static class ItemViewHolder extends RecyclerView.ViewHolder {
        TextView textView;

        ItemViewHolder(View itemView) {
            super(itemView);
            textView = itemView.findViewById(R.id.text_view);
        }
    }
}

Important methods of Adapter

In the constructor of this adapter, we are getting an arraylist with objects of the interface “Section

This arraylist contains the objects of both ChildModel and HeaderModel.

I will explain this arraylist in Main Activity, but for now we will just use it.

Consider the below code

@Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());

        if (viewType == LAYOUT_HEADER ) {
            return new HeaderViewholder(inflater.inflate(R.layout.recycler_view_header_item, parent, false));
        }else {
            return new ItemViewHolder(inflater.inflate(R.layout.recycler_view_item, parent, false));
        }
    }

Above method is inflating required XML file : recycler_view_header_item.xml or recycler_view_item.xml

If viewType is header than compiler will inflate recycler_view_header_item.xml file which is representing the header view.

Otherwise it will inflate the recycler_view_item.xml.

Read the following method

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

        if (sectionArrayList.get(position).isHeader()) {
            ((HeaderViewholder) holder).textView.setText( sectionArrayList.get(position).getName());
        } else {
            ((ItemViewHolder) holder).textView.setText(sectionArrayList.get(position).getName());
        }
    }

This method is setting the text in the textview.

Compiler will use isHeader() method (from interface) to decide whether the item is header or child.

And according to that, it will select the textview to write the name.

Step 6. Main Activity Files

Last but not least, let us make some necessary changes in the main files.

Source Code block for activity_main.xml should look like the below

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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"
    tools:context=".MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</android.support.constraint.ConstraintLayout>
  • In this file, I have just taken one recyclerview.

In the MainActivity.java file, write the following source code

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

public class MainActivity extends AppCompatActivity {

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

    private ArrayList<Section> sectionArrayList;

    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","Khachhar","Horse 2","Camel 2","Donkey 2","Tesla","Mercedes"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        RecyclerView recyclerView = findViewById(R.id.recycler_view);

        recyclerView.setLayoutManager(new LinearLayoutManager(this));

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

        SectionAdapter adapter = new SectionAdapter(this,sectionArrayList);
        recyclerView.setAdapter(adapter);
        StickyHeaderItemDecorator decorator = new StickyHeaderItemDecorator(adapter);
        decorator.attachToRecyclerView(recyclerView);



    }

    private void populateList(){

        int headerdone = 0, childdone = 0;

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

            if(i == 0 || i == 5 | i == 10 | i == 15){

                    HeaderModel vehicleModel = new HeaderModel(i);
                    vehicleModel.setheader(vehicleTypes[headerdone]);
                    sectionArrayList.add(vehicleModel);
                    headerdone = headerdone + 1;
            }else {

                    ChildModel childModel = null;
                    if(i == 1 || i == 2 || i ==3 || i == 4){
                        childModel = new ChildModel(0);
                    }else if(i == 6 || i == 7 || i == 8 || i == 9){
                        childModel = new ChildModel(5);
                    }else if(i == 11 || i == 12 || i == 13 || i == 14){
                        childModel = new ChildModel(10);
                    }else {
                        childModel = new ChildModel(15);
                    }

                    childModel.setChild(childnames[childdone]);
                    sectionArrayList.add(childModel);
                    childdone = childdone + 1;
            }
        }

    }
}

Going Inside Main Activity

Consider the below source code

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

    private ArrayList<Section> sectionArrayList;

    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","Khachhar","Horse 2","Camel 2","Donkey 2","Tesla","Mercedes"};

Second line is creating an arraylist of the objects of the Section Interface.

First line is making a string array which contains the types of the vehicles.

This string array will provide the headers of the RecyclerView.

Third line is also making one string array which is giving us children names for our RecyclerView.

Read the following

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

First one is simply initializing the arraylist.

Second one is calling a method populateList()

Code block for populateList() is as the below

  private void populateList(){

        int headerdone = 0, childdone = 0;

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

            if(i == 0 || i == 5 | i == 10 | i == 15){

                    HeaderModel vehicleModel = new HeaderModel(i);
                    vehicleModel.setheader(vehicleTypes[headerdone]);
                    sectionArrayList.add(vehicleModel);
                    headerdone = headerdone + 1;
            }else {

                    ChildModel childModel = null;
                    if(i == 1 || i == 2 || i ==3 || i == 4){
                        childModel = new ChildModel(0);
                    }else if(i == 6 || i == 7 || i == 8 || i == 9){
                        childModel = new ChildModel(5);
                    }else if(i == 11 || i == 12 || i == 13 || i == 14){
                        childModel = new ChildModel(10);
                    }else {
                        childModel = new ChildModel(15);
                    }

                    childModel.setChild(childnames[childdone]);
                    sectionArrayList.add(childModel);
                    childdone = childdone + 1;
            }
        }

    }

In this method, compiler will create one for loop with 26 iterations.

26 is the number equal to the number of children items + header items.

You should change this number as per the number of children items + header items. in your project.

if condition ( if(i == 0 || i == 5 | i == 10 | i == 15) ) is true when there are headers.

At this time, compiler will create the object of the HeaderModel class and will add it to the arralist.

When the if condition is false, compiler will create the object of the ChildModel class and will add it to the arraylist.

   SectionAdapter adapter = new SectionAdapter(this,sectionArrayList);
        recyclerView.setAdapter(adapter);
        StickyHeaderItemDecorator decorator = new StickyHeaderItemDecorator(adapter);
        decorator.attachToRecyclerView(recyclerView);

Finally, above code will create an object of the adapter class.

And then it will add the adapter object to the RecyclerView.

Download Source Code For Android RecyclerView Sticky Header Like iphone

[sociallocker]Download Source Code For RecyclerView_StickyHeader_Iphone[/sociallocker]