How to use TabLayout in ViewPager with RecyclerView

How to use TabLayout in ViewPager with RecyclerView

ViewPagers are used to swipe through pages of data. It’s generally used in conjunction with fragments. In this tutorial, we’ll be implementing a ViewPager under the TabLayout.

ViewPagers is introduced in this year 2019 Google I/O and is a replacement of the old ViewPager, which was created in 2011. It includes some new features to enhance UI and coding experience.

So for that, we need to use Android Material Design Tabs for implementing tabs in our app. We have to see like Google Play Store, Whatsapp and many applications are using Android Material Design Tabs.

Android TabLayout ViewPager

Let’s modify our layout from the previous tutorial as below.

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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=".activities.PackageActivity">
    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@null"
        android:paddingBottom="5dp"
        app:elevation="0dp">
        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:layout_collapseMode="pin"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
        <com.google.android.material.tabs.TabLayout
            android:id="@+id/packagetablayout"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            app:tabGravity="fill"
            app:tabMode="scrollable"/>
    </com.google.android.material.appbar.AppBarLayout>
    <androidx.viewpager.widget.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

 

The output of the project:

Fragment 1
Fragment 2

Android TabLayout ViewPager Example Code

Before we add up our ViewPager in the MainActivity, let’s set up its the adapter.

Loading...
PackageTabAdapter.java
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;
import com.google.android.material.tabs.TabLayout;
import com.legendcode.weekends.fragments.DomesticFragment;
import com.legendcode.weekends.fragments.InternationalFragment;
public class PackageTabAdapter extends FragmentStatePagerAdapter {
    TabLayout tabLayout;
    public PackageTabAdapter(FragmentManager fm, TabLayout _tabLayout) {
        super(fm);
        this.tabLayout = _tabLayout;
    }
    @Override
    public Fragment getItem(int position) {
        Fragment fragment = null;
        if (position == 0)
        {
            fragment = new DomesticFragment();
        }
        else if (position == 1)
        {
            fragment = new InternationalFragment();
        }
        return fragment;
    }
    @Override
    public int getCount() {
        return 2;
    }
    @Override
    public CharSequence getPageTitle(int position) {
        String title = null;
        if (position == 0)
        {
            title = "Domestic";
        }
        else if (position == 1)
        {
            title = "International";
        }
        return title;
    }
}

In the above code setupWithViewPager() is used to join the TabLayout with the ViewPager. The getPageTitle() method in the FragmentStatePagerAdapter is used to set the title of each of the Tabs. Let’s look at the output when the above code is run.

PackageActivity.java

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.viewpager.widget.ViewPager;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import com.google.android.material.tabs.TabLayout;
import com.legendcode.weekends.R;
import com.legendcode.weekends.adapter.PackageTabAdapter;
public class PackageActivity extends AppCompatActivity {
    private String TAG = "PackageActivity";
    private Context context;
    private Toolbar toolbar;
    public static TabLayout tabLayout;
    public static ViewPager viewPager;
    private PackageTabAdapter adapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_package);
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        if(getSupportActionBar() == null) {
            setSupportActionBar(toolbar);
        }else toolbar.setVisibility(View.GONE);
        getSupportActionBar().setTitle("Packages");
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        viewPager = (ViewPager) findViewById(R.id.viewPager);
        viewPager.setOffscreenPageLimit(2);
        tabLayout = (TabLayout) findViewById(R.id.packagetablayout);
        createTabFragment();
    }
    private void createTabFragment(){
        adapter = new PackageTabAdapter(getSupportFragmentManager(), tabLayout);
        viewPager.setAdapter(adapter);
        tabLayout.setupWithViewPager(viewPager);
    }
    @Override
    public boolean onSupportNavigateUp() {
        onBackPressed();
        return true;
    }
}

Create the data model of list:

Product.java

import android.os.Parcel;
import android.os.Parcelable;
import java.util.List;
public class Product implements Parcelable {
    private String image;
    private String id;
    private String title;
    private String description;
    private String price;
    private String cut_price;
    private String discount;
    private float rating;
    private String external_link;
    public Product(String image, String id, String title, String description, String price, String cut_price, String discount, float rating) {
        this.image = image;
        this.id = id;
        this.title = title;
        this.description = description;
        this.price = price;
        this.cut_price = cut_price;
        this.discount = discount;
        this.rating = rating;
    }
    public Product(String image, String title, String description, String price, String cut_price, String discount, float rating) {
        this.image = image;
        this.title = title;
        this.description = description;
        this.price = price;
        this.cut_price = cut_price;
        this.discount = discount;
        this.rating = rating;
    }
    public Product(String image, String title, String description, String price, String cut_price, String discount, float rating, String external_link) {
        this.image = image;
        this.title = title;
        this.description = description;
        this.price = price;
        this.cut_price = cut_price;
        this.discount = discount;
        this.rating = rating;
        this.external_link = external_link;
    }
    @Override
    public int describeContents() {
        return 0;
    }
    @Override
    public void writeToParcel(Parcel out, int flags) {
        out.writeString(image);
        out.writeString(title);
        out.writeString(description);
        out.writeString(price);
        out.writeString(cut_price);
        out.writeString(discount);
        out.writeFloat(rating);
        out.writeString(external_link);
    }
    public static final Parcelable.Creator<Product> CREATOR = new Parcelable.Creator<Product>() {
        public Product createFromParcel(Parcel in) {
            return new Product(in);
        }
        public Product[] newArray(int size) {
            return new Product[size];
        }
    };
    private Product(Parcel in) {
        image = in.readString();
        title = in.readString();
        description = in.readString();
        price = in.readString();
        cut_price = in.readString();
        discount = in.readString();
        rating = in.readFloat();
        external_link = in.readString();
    }
    public String getImage() {
        return image;
    }
    public void setImage(String image) {
        this.image = image;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public String getPrice() {
        return price;
    }
    public void setPrice(String price) {
        this.price = price;
    }
    public String getCut_price() {
        return cut_price;
    }
    public void setCut_price(String cut_price) {
        this.cut_price = cut_price;
    }
    public String getDiscount() {
        return discount;
    }
    public void setDiscount(String discount) {
        this.discount = discount;
    }
    public float getRating() {
        return rating;
    }
    public void setRating(float rating) {
        this.rating = rating;
    }
    public String getExternal_link() {
        return external_link;
    }
    public void setExternal_link(String external_link) {
        this.external_link = external_link;
    }
}

Now create two Fragment pages:

Loading...

DomesticFragment.java

package com.legendcode.weekends.fragments;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.legendcode.weekends.R;
import com.legendcode.weekends.adapter.PackageViewAdapter;
import com.legendcode.weekends.model.Product;
import java.util.ArrayList;
/**
 * A simple {@link Fragment} subclass.
 */
public class DomesticFragment extends Fragment {
    private Context context;
    private RecyclerView recyclerView;
    private PackageViewAdapter packageViewAdapter;
    private ArrayList<Product> productList = new ArrayList<>();
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_domestic, container, false);
    }
    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        this.context = getContext();
        recyclerView = view.findViewById(R.id.recyclerView);
        populateData();
        packageViewAdapter = new PackageViewAdapter(context, productList);
        recyclerView.setAdapter(packageViewAdapter);
    
    }
    private void populateData() {
        productList.add(new Product("image_1", "Android", getString(R.string.lorem), "4999", "5999", "10% off", 4.2f));
        productList.add(new Product("image_2", "Beta", getString(R.string.lorem), "6999", "8999", "15% off", 4.6f));
        productList.add(new Product("image_3", "Cupcake", getString(R.string.lorem), "4999", "5999", "10% off", 3.2f));
        productList.add(new Product("image_4", "Donut", getString(R.string.lorem), "4999", "5999", "10% off", 4.1f));
        productList.add(new Product("image_5", "Eclair", getString(R.string.lorem), "4999", "5999", "10% off", 4.8f));
        productList.add(new Product("image_6", "Froyo", getString(R.string.lorem), "9999", "10999", "10% save now", 3.6f));
        productList.add(new Product("image_1", "Gingerbread", getString(R.string.lorem), "4999", "5999", "10% off", 2.8f));
        productList.add(new Product("image_2", "Ice Cream Sandwich", getString(R.string.lorem), "4999", "5999", "10% off", 4.1f));
        productList.add(new Product("image_3", "Jelly Bean", getString(R.string.lorem), "3999", "4999", "10% off", 4.5f));
        productList.add(new Product("image_4", "Lollipop", getString(R.string.lorem), "4999", "5999", "10% off", 4.0f));
        productList.add(new Product("image_5", "Marshmallow", getString(R.string.lorem), "4999", "5999", "10% save now", 5.0f));
        productList.add(new Product("image_6", "Nougat", getString(R.string.lorem), "5999", "7999", "10% off", 4.1f));
        productList.add(new Product("image_1", "Oreo", getString(R.string.lorem), "4999", "5999", "10% off", 3.9f));
    }
}

fragment_domestic.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context=".fragments.DomesticFragment">
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layoutAnimation="@anim/layout_animation_right_to_left"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
</FrameLayout>

The second Fragment is:

InternationalFragment.java

import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.legendcode.weekends.R;
import com.legendcode.weekends.adapter.PackageViewAdapter;
import com.legendcode.weekends.model.Product;
import java.util.ArrayList;
/**
 * A simple {@link Fragment} subclass.
 */
public class InternationalFragment extends Fragment {
    private Context context;
    private RecyclerView recyclerView;
    PackageViewAdapter packageViewAdapter;
    private ArrayList<Product> productList = new ArrayList<>();
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_international, container, false);
    }
    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        this.context = getContext();
        recyclerView = view.findViewById(R.id.recyclerView);
        populateData();
        packageViewAdapter = new PackageViewAdapter(context, productList);
        recyclerView.setAdapter(packageViewAdapter);
    }
    private void populateData() {
        productList.add(new Product("image_1", "Android", getString(R.string.lorem), "4999", "5999", "10% off", 4.2f));
        productList.add(new Product("image_2", "Beta", getString(R.string.lorem), "6999", "8999", "15% off", 4.6f));
        productList.add(new Product("image_3", "Cupcake", getString(R.string.lorem), "4999", "5999", "10% off", 3.2f));
        productList.add(new Product("image_4", "Donut", getString(R.string.lorem), "4999", "5999", "10% off", 4.1f));
        productList.add(new Product("image_5", "Eclair", getString(R.string.lorem), "4999", "5999", "10% off", 4.8f));
        productList.add(new Product("image_6", "Froyo", getString(R.string.lorem), "9999", "10999", "10% save now", 3.6f));
        productList.add(new Product("image_1", "Gingerbread", getString(R.string.lorem), "4999", "5999", "10% off", 2.8f));
        productList.add(new Product("image_2", "Ice Cream Sandwich", getString(R.string.lorem), "4999", "5999", "10% off", 4.1f));
        productList.add(new Product("image_3", "Jelly Bean", getString(R.string.lorem), "3999", "4999", "10% off", 4.5f));
        productList.add(new Product("image_4", "Lollipop", getString(R.string.lorem), "4999", "5999", "10% off", 4.0f));
        productList.add(new Product("image_5", "Marshmallow", getString(R.string.lorem), "4999", "5999", "10% save now", 5.0f));
        productList.add(new Product("image_6", "Nougat", getString(R.string.lorem), "5999", "7999", "10% off", 4.1f));
        productList.add(new Product("image_1", "Oreo", getString(R.string.lorem), "4999", "5999", "10% off", 3.9f));
    }
}

fragment_international.xml

Loading...
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context=".fragments.DomesticFragment">
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layoutAnimation="@anim/layout_animation_right_to_left"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
</FrameLayout>

Now create Adapter for showing the above model list in both Fragments:

PackageViewAdapter.java

import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RatingBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.legendcode.weekends.R;
import com.legendcode.weekends.activities.DetailActivity;
import com.legendcode.weekends.model.Product;
import java.util.ArrayList;
public class PackageViewAdapter extends RecyclerView.Adapter<PackageViewAdapter.MyViewHolder> {
    private Context context;
    private ArrayList<Product> dataModel;
    private int width, height;
    public static class MyViewHolder extends RecyclerView.ViewHolder {
        ImageView image_view;
        TextView text_title;
        TextView price;
        TextView discount;
        TextView cut_price;
        RatingBar rating;
        RelativeLayout price_bar;
        RelativeLayout cut_rate_bar;
        View itemView;
        public MyViewHolder(View view) {
            super(view);
            this.image_view = (ImageView) view.findViewById(R.id.image_view);
            this.text_title = (TextView) view.findViewById(R.id.title);
            this.price = (TextView) view.findViewById(R.id.price);
            this.discount = (TextView) view.findViewById(R.id.discount);
            this.cut_price = (TextView) view.findViewById(R.id.cut_price);
            this.rating = (RatingBar) view.findViewById(R.id.rating);
            this.price_bar = (RelativeLayout) view.findViewById(R.id.price_bar);
            this.cut_rate_bar = (RelativeLayout) view.findViewById(R.id.cut_rate_bar);
            this.itemView = view;
        }
    }
    public PackageViewAdapter(Context _context, ArrayList<Product> data) {
        this.context = _context;
        this.dataModel = data;
        this.width = 160;
        this.height = 100;
    }
    public PackageViewAdapter(Context _context, ArrayList<Product> data, int _width, int _height) {
        this.context = _context;
        this.dataModel = data;
        this.width = _width;
        this.height = _height;
    }
    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent,
                                           int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.package_list, parent, false);
        // view.setOnClickListener(MainActivity.myOnClickListener);
        MyViewHolder myViewHolder = new MyViewHolder(view);
        return myViewHolder;
    }
    @Override
    public void onBindViewHolder(final MyViewHolder holder, final int position) {
        try{
            Glide.with(holder.itemView)
                    .load(getImage(dataModel.get(position).getImage()))
                    .fitCenter()
                    .into(holder.image_view);
            holder.text_title.setText(dataModel.get(position).getTitle());
            holder.price.setText(context.getString(R.string.price, dataModel.get(position).getPrice()));
            holder.cut_price.setText(context.getString(R.string.price, dataModel.get(position).getCut_price()));
            holder.discount.setText(dataModel.get(position).getDiscount());
            holder.rating.setRating(dataModel.get(position).getRating());
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Intent intent = new Intent(context, DetailActivity.class);
                    intent.putExtra("dataSet", dataModel.get(position));
                    //ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(context, holder.image_view, "robot");
                    context.startActivity(intent);
                }
            });
        }catch (Exception e){e.printStackTrace();}
    }
    private int getImage(String imageName) {
        int drawableResourceId = context.getResources().getIdentifier(imageName, "drawable", context.getPackageName());
        return drawableResourceId;
    }
    @Override
    public int getItemCount() {
        return dataModel.size();
    }
}

Before adding the above adapter you need to add this layout for the list:

package_list.xml

<?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:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cardUseCompatPadding="true"
    app:cardCornerRadius="8dp"
    app:cardElevation="10dp">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <ImageView
            android:id="@+id/image_view"
            android:layout_width="match_parent"
            android:layout_height="150dp"
            android:scaleType="centerCrop"
            android:src="@drawable/image_1"/>
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="10dp">
            <RelativeLayout
                android:id="@+id/title_bar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">
                <TextView
                    android:id="@+id/title"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="@string/packages"
                    android:lines="1"
                    android:textSize="16sp" />
            </RelativeLayout>
            <RelativeLayout
                android:id="@+id/price_bar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@+id/title_bar">
                <TextView
                    android:id="@+id/price"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentStart="true"
                    android:text="Rs. 4999"
                    android:textSize="18sp" />
                <TextView
                    android:id="@+id/discount"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentRight="true"
                    android:layout_centerVertical="true"
                    android:text="10% off"
                    android:textColor="@color/colorPrimary"
                    android:textSize="16sp" />
            </RelativeLayout>
            <RelativeLayout
                android:id="@+id/cut_rate_bar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@+id/price_bar">
                <TextView
                    android:id="@+id/cut_price"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentStart="true"
                    android:background="@drawable/strike_through"
                    android:text="Rs. 5999"
                    android:textSize="14sp" />
                <RatingBar
                    android:id="@+id/rating"
                    style="@style/wkRatingBar"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentRight="true"
                    android:layout_centerVertical="true"
                    android:numStars="5"
                    android:rating="1.7"
                    android:saveEnabled="true"
                    android:stepSize="0.1" />
            </RelativeLayout>
        </RelativeLayout>
    </LinearLayout>
</androidx.cardview.widget.CardView>

Related posts

(1) Comments

  • User Pic

    Thankful to gain knowledge from these extremely informational blogs.
    I am stuck at "PackageViewAdapter.java", in the lines
    ( holder.price.setText(context.getString(R.string.price, dataModel.get(position).getPrice()));
    holder.cut_price.setText(context.getString(R.string.price, dataModel.get(position).getCut_price())); ), at the string "price" ,
    from the "How to use TabLayout in ViewPager with RecyclerView" blog. Can you share me or give me the link for this project on GitHub.
    Thank you in advance.

Write a comment