Close
Close full mode
logoAppDevAssist

How to combine TabLayout with ViewPager2 and NavGraph in Android

How to combine TabLayout with ViewPager2 and NavGraph in Android:

In this post, we will learn how to combine TabLayout, ViewPager2 and NavGraph. TabLayout is used to create a tab bar and for each tab, we can add one Fragment. ViewPager is used to create a swipable view. ViewPager2 has a couple of advantages over ViewPager. We can combine TabLayout and ViewPager2 with a NavGraph. The NavGraph will hold the references to the fragments.

I am not going in detail on how to create android projects, add fragments to NavGraph etc. on this post. If you want to learn from basics, you can visit my YouTube channel to learn them all before you move further on this tutorial.

YouTube video:

I have published one video on YouTube explaining this process. You can watch it here:

Create three fragments:

Let's create three fragments to add to the NavGraph. These fragments will be added to the TabLayout and ViewPager.

Following are the fragments I am creating for this example:

  1. FirstFragment.kt, its xml file is fragment_first.xml
  2. SecondFragment.kt, its xml file is fragment_second.xml
  3. ThirdFragment.kt, its xml file is fragment_third.xml

All fragments are similar. Only the background color for each fragment is different.

For example, below is the code for FirstFragment.kt:

import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.nk.navigationgraphdrawer.R
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"
/**
* A simple [Fragment] subclass.
* Use the [FirstFragment.newInstance] factory method to
* create an instance of this fragment.
*/
class FirstFragment : Fragment() {
// TODO: Rename and change types of parameters
private var param1: String? = null
private var param2: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_first, container, false)
}
companion object {
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment FirstFragment.
*/
// TODO: Rename and change types and number of parameters
@JvmStatic
fun newInstance(param1: String, param2: String) =
FirstFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
fun newInstance() =
FirstFragment()
}
}

and fragment_first.xml file:

<?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"
android:background="#2196F3"
tools:context=".fragments.FirstFragment" />

You can create the other fragments similarly with different background color for each.

Create one NavGraph and add the fragments to the graph:

Create one navigation graph main_graph.xml and add all three fragments to it.

The xml code for the navigation graph is:

<?xml version="1.0" encoding="utf-8"?>
<navigation 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:id="@+id/main_graph"
app:startDestination="@id/firstFragment">
<fragment
android:id="@+id/firstFragment"
android:name="com.nk.navigationgraphdrawer.fragments.FirstFragment"
android:label="fragment_first"
tools:layout="@layout/fragment_first" />
<fragment
android:id="@+id/secondFragment"
android:name="com.nk.navigationgraphdrawer.fragments.SecondFragment"
android:label="fragment_second"
tools:layout="@layout/fragment_second" />
<fragment
android:id="@+id/thirdFragment"
android:name="com.nk.navigationgraphdrawer.fragments.ThirdFragment"
android:label="fragment_third"
tools:layout="@layout/fragment_third" />
</navigation>

MainActivity and its xml file:

The start activity is MainActivity.kt and its xml file is activity_main.xml. Add one toolbar, tablayout and viewpager to the activity_main.xml:

<?xml version="1.0" encoding="utf-8"?><!-- Use DrawerLayout as root container for activity -->
<FrameLayout 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:fitsSystemWindows="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</FrameLayout>

Now, inside MainActivity.kt, we can do all bindings:

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.fragment.app.Fragment
import androidx.navigation.NavController
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 com.nk.navigationgraphdrawer.fragments.FirstFragment
import com.nk.navigationgraphdrawer.fragments.SecondFragment
import com.nk.navigationgraphdrawer.fragments.ThirdFragment
class MainActivity : AppCompatActivity() {
lateinit var navController: NavController
lateinit var toolbar: Toolbar
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
toolbar = findViewById(R.id.toolbar)
val tabLayout = findViewById<TabLayout>(R.id.tabLayout)
val viewPager = findViewById<ViewPager2>(R.id.viewPager)
viewPager.adapter = FragmentAdapter(this)
TabLayoutMediator(tabLayout, viewPager){tab, position ->
tab.text = "Tab ${position}"
}.attach()
}
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp() || super.onSupportNavigateUp()
}
class FragmentAdapter(activity: AppCompatActivity) : FragmentStateAdapter(activity){
override fun getItemCount(): Int {
return 3
}
override fun createFragment(position: Int): Fragment {
return when(position){
0 -> FirstFragment.newInstance()
1 -> SecondFragment.newInstance()
2 -> ThirdFragment.newInstance()
else -> FirstFragment.newInstance()
}
}
}
}

Here,

  • We have created one adapter FragmentAdapter which is responsible to load the fragment based on the tab position.
  • TabLayoutMediator defines the text to show in the tab based on the current position.

If you run this program, it will be as like below:

Android tablayout viewpager2 navgraph
Android tablayout viewpager2 navgraph

Source code (branch: tabbar_viewpager2)

Subscribe to our Newsletter

Previous
How to create RadioGroup and RadioButtons in Android
Next
How to create a custom Navigation drawer in Kotlin with Day-Night toggle