TabLayout with ViewPager2 Tutorial in Android

TabLayout with ViewPager2 in Android | Vertical & RTL Paging Example

TabLayout with ViewPager2 in Android

Author: Deep Singh | Category: Android, Java, UI Components

Introduction

ViewPager2 is an enhanced version of the classic ViewPager view in Android. It provides improved performance, vertical paging support, RTL (Right-to-Left) layout support, and seamless integration with TabLayout via TabLayoutMediator.

Android ViewPager2 vertical paging animation with TabLayout
Figure 1: ViewPager2 vertical paging in action

Advantages of ViewPager2

  1. Vertical paging support: ViewPager2 supports vertical paging, meaning you can scroll pages in a vertical direction.

    To enable vertical paging in XML, use:

    android:orientation="vertical"
  2. Enable vertical paging via Java code:

    viewPager.setOrientation(ViewPager2.ORIENTATION_VERTICAL);
  3. RTL (Right-To-Left) paging support: ViewPager2 supports RTL paging out of the box.

    RTL paging is enabled automatically based on locale, but you can also enable it manually:

    android:layoutDirection="rtl"
  4. Enable RTL direction via Java code:

    viewPager.setLayoutDirection(LAYOUT_DIRECTION_RTL);
  5. Fragment collection updates: ViewPager2 supports paging through a modified collection of fragments, calling notifyDatasetChanged() to update the UI when your fragment collection changes.

Complete Example of ViewPager2 with TabLayout

The following example demonstrates a working implementation of TabLayout + ViewPager2 with three tabs: Login, Register, and Extra.

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <androidx.appcompat.widget.Toolbar
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:title="TabLayout with ViewPager2"
            app:titleTextColor="@color/white" />

        <com.google.android.material.tabs.TabLayout
            android:id="@+id/tabbed"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

    </com.google.android.material.appbar.AppBarLayout>

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" />

</LinearLayout>

extra.xml

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

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="Extra"
        android:textSize="30sp" />

</RelativeLayout>

register.xml

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

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="Register"
        android:textSize="30sp" />

</RelativeLayout>

login.xml

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

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="Login"
        android:textSize="30sp" />

</RelativeLayout>

MainActivity.java

package com.example.firstapp;

import android.annotation.SuppressLint;
import android.os.Build;
import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;

import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;

import org.jetbrains.annotations.NotNull;

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

public class MainActivity extends AppCompatActivity {

    // Create a fragments collection
    List<Fragment> fragments = new ArrayList<>();
    // Create a titles collection
    List<String> titles = new ArrayList<>();

    @SuppressLint("WrongConstant")
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Add fragments into the fragment collection
        fragments.add(new LoginFragment());
        fragments.add(new RegisterFragment());
        fragments.add(new ExtraFragment());

        // Add titles into the title collection
        titles.add("Login");
        titles.add("Register");
        titles.add("Extra");

        TabLayout tabLayout = findViewById(R.id.tabbed);
        ViewPager2 viewPager = findViewById(R.id.viewpager);

        // Optional: enable vertical paging
        // viewPager.setOrientation(ViewPager2.ORIENTATION_VERTICAL);

        // Optional: enable RTL layout direction
        // viewPager.setLayoutDirection(LAYOUT_DIRECTION_RTL);

        viewPager.setAdapter(new MyWhatsAppTab(this));

        // TabLayoutMediator is a callback interface that must be implemented
        // to set the text and styling of newly created tabs.
        // It links TabLayout and ViewPager2 together.
        // Must be called after ViewPager2 has an adapter set.
        new TabLayoutMediator(tabLayout, viewPager,
                (tab, position) -> tab.setText(titles.get(position))
        ).attach();
    }

    class MyWhatsAppTab extends FragmentStateAdapter {

        public MyWhatsAppTab(@NonNull @NotNull FragmentActivity fragmentActivity) {
            super(fragmentActivity);
        }

        @NonNull
        @NotNull
        @Override
        public Fragment createFragment(int position) {
            return fragments.get(position);
        }

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

RegisterFragment.java

package com.example.firstapp;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import org.jetbrains.annotations.NotNull;

public class RegisterFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(@NonNull @NotNull LayoutInflater inflater,
                             @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.register, container, false);
    }
}

ExtraFragment.java

package com.example.firstapp;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import org.jetbrains.annotations.NotNull;

public class ExtraFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(@NonNull @NotNull LayoutInflater inflater,
                             @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.extra, container, false);
    }
}

LoginFragment.java

package com.example.firstapp;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import org.jetbrains.annotations.NotNull;

public class LoginFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(@NonNull @NotNull LayoutInflater inflater,
                             @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.login, container, false);
    }
}

Conclusion

ViewPager2 is a powerful and modern replacement for the deprecated ViewPager. Combined with TabLayout and TabLayoutMediator, it provides a clean, flexible way to build swipeable tabbed interfaces in Android.

Key takeaways from this tutorial:

  • Vertical paging is natively supported via android:orientation="vertical" or setOrientation().
  • RTL support works automatically based on locale, or can be forced via android:layoutDirection="rtl".
  • FragmentStateAdapter is the recommended adapter for fragment-based pages.
  • TabLayoutMediator links TabLayout and ViewPager2 seamlessly and must be attached after the adapter is set.
  • UI updates are handled via notifyDatasetChanged() when the fragment collection changes.

By following this example, you can easily integrate TabLayout with ViewPager2 into your own Android app to create smooth, modern, swipeable tab interfaces. Try extending the example by adding more fragments, custom tab icons, or combining it with RecyclerView for even richer UI experiences.