arrow left
Back to Developer Education

    Android ViewPager2 with TabLayout

    Android ViewPager2 with TabLayout

    Slide transition between screens is common in Android applications. We can use the navigation components or a swipe-able view to create this transition. A common swipe-able view is ViewPager2. The ViewPager library has been around for quite a while. <!--more-->

    Introduction

    This view allows the developer to display views or fragments to the user in a swipe-able format. This feature is common in content display applications and in app setups.

    ViewPager2 is often integrated with TabLayout. A TabLayout indicates the current page and allows a user to switch through pages.

    ViewPager2 is a newer version of the ViewPager library. A significant difference from the old library is the use of a RecyclerView adapter. With this, views are now recycled. This improves user experience by making smooth transitions and minimizing memory usage.

    This article goes through implementing ViewPager2 and TabLayout in an Android application.

    Let's dive in!

    Prerequisites

    To follow through with this tutorial, you will need to:

    1. Have Android Studio installed.
    2. Have a basic knowledge of building Android applications.
    3. Have a basic understanding of Kotlin programming language.

    Let's get started!

    Step 1 — Creating an Android Project

    In this step, we're going to create our application. Open Android Studio and start a new project using the empty activity template. On the next page, give the application a name and keep the default settings.

    app name

    Click Finish and wait for the project build process to finish.

    Step 2 — Adding Views in Xml Layouts

    Our activity_main layout file will contain only two views. Add them as follows.

    <com.google.android.material.tabs.TabLayout
        android:id="@+id/tabLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
    
    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_marginTop="5dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tabLayout" />
    

    We also need to create a layout that we'll display on the ViewPager2 component. Go to File -> New -> XML -> Layout XML File to create the layout file. In the layout file, replace the default TextView widget with the one below.

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@color/black"
        android:textSize="50sp"
        tools:text="TextView"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    

    We're done with the xml files. Let's go ahead and create an adapter for our ViewPager2 component.

    Step 3 — Creating ViewPager2 adapter

    As I mentioned earlier, the ViewPager2 component uses a recyclerview adapter. The adapter's responsibility is to render data to the viewPager2 component. The recyclerview adapter adds vertical scroll ability, which was absent in the old ViewPager. We will show this ability later in the article.

    Let's start creating the adapter.

    Go to File -> New -> Kotlin File/Class. Select class and name the file PagerAdapter.

    In the adapter class, add the following code.

    class PagerAdapter(private val context: Context, private val words: List<String>): RecyclerView.Adapter<PagerAdapter.PageHolder>(){
    
    }
    

    This adds the constructor and extends the base class RecyclerView.Adapter. The base class takes a typed parameter which is a view holder. The PagerAdapter.PageHolder class is a view holder class that we are yet to create.

    Inside the PagerAdapter class, add the PageHolder class as an inner class.

    inner class PageHolder(view: View): RecyclerView.ViewHolder(view){
    
    }
    

    The class needs to extend the base class RecyclerView.ViewHolder. It should also pass in the view it gets as a parameter. A ViewHolder, as the name suggests, is a class that holds and describe views that each list item should contain. We create our view references in this class.

    Let's add our view's reference to the view holder.

    inner class PageHolder(view: View): RecyclerView.ViewHolder(view){
          val textView: TextView = view.textView
    }
    

    Now override the members of the RecyclerView.Adapter class. We only need to override these three members.

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PageHolder {
    
    }
    
    override fun onBindViewHolder(holder: PageHolder, position: Int) {
    
    }
    
    override fun getItemCount(): Int {
    
    }
    

    Read this article for a deeper explanation of the methods.

    Add the implementation to the methods as shown below.

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PageHolder  =
            PageHolder(LayoutInflater.from(context).inflate(R.layout.page_layout, parent, false))
    }
    
    override fun onBindViewHolder(holder: PageHolder, position: Int) {
          holder.textView.text = words[position]
    }
    
    override fun getItemCount(): Int = words.size
    

    In the onCreateViewHolder method, we inflate the page_layout layout using a LayoutInflater. In the onBindViewHolder method, we assign a word from the word list to the TextView. The getItemCount is a method where we return the size of the word list.

    That's all for the adapter.

    Step 4 — Testing the ViewPager2 component

    Open MainActivity.kt file. In the onCreate method, add a list of words.

    val words = arrayListOf("One", "Two", "Three", "Four", "Five")
    

    Then add the adapter as shown.

    pager.adapter = PagerAdapter(this, words)
    

    That's what we need for the ViewPager2. Now build and run the application.

    The output should look like this.

    View pager gif

    To change the scroll orientation to vertical, add the following statement in the onCreate method.

    pager.orientation = ViewPager2.ORIENTATION_VERTICAL
    

    It should resemble the demo below.

    vertical orientation gif

    Step 5 — Integrating TabLayout

    Now that our view pager is functioning as expected. Let's go ahead and integrate it with TabLayout.

    To integrate ViewPager2 with TabLayout we need to use a TabLayoutMediator class. This was easier with the old ViewPager. We had to use the TabLayout's setUpWithViewPager method and pass the ViewPager2 reference.

    The TabLayoutMediator class takes in two parameters, the TabLayout and ViewPager2 references.

    TabLayoutMediator(tabLayout, pager)
    

    The class then takes a lambda function with two parameters. TabLayout.Tab and an integer representing the position of the ViewPagers' pages.

    TabLayoutMediator(tabLayout, pager) {tab, position ->
          tab.text = "${position + 1}"
    }.attach()
    

    In the function, we set the tabs' text to the position plus one. We add one because the positions start from zero. We attach the components by calling the attach method.

    Build and run the application. This is how it should look.

    tab layout gif

    Another essential feature of TabLayout is the onTabSelectedListener. This notifies the listeners whenever a tab's selected, unselected, or reselected. This is useful when one wants to perform some background tasks when the listener fires up. We'll use toasts in our application for demonstration.

    Add the following code to implement the feature.

    tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
        override fun onTabSelected(tab: TabLayout.Tab?) {
            Toast.makeText(this@MainActivity, "Tab ${tab?.text} selected", Toast.LENGTH_SHORT).show()
        }
    
        override fun onTabUnselected(tab: TabLayout.Tab?) {
            Toast.makeText(this@MainActivity, "Tab ${tab?.text} unselected", Toast.LENGTH_SHORT).show()
        }
    
        override fun onTabReselected(tab: TabLayout.Tab?) {
            Toast.makeText(this@MainActivity, "Tab ${tab?.text} reselected", Toast.LENGTH_SHORT).show()
        }
    })
    

    Build and rerun the app.

    https://sparkling-desk-070a6c243e.media.strapiapp.com/2227_toasts_be84bb3913.gif

    Conclusion

    In this article, we have gone through creating the ViewPager2 component. We have also seen how we can integrate it with a TabLayout. This is a common UI component, and almost all apps that display data in page format use it.

    Achieving the slide transition between content screens is relatively easy with the component. You don't need to implement gesture listeners since the component does that for you. You can find the app's source code on Github.


    Peer Review Contributions by: Linus Muema

    Published on: Nov 22, 2020
    Updated on: Jul 15, 2024
    CTA

    Start your journey with Cloudzilla

    With Cloudzilla, apps freely roam across a global cloud with unbeatable simplicity and cost efficiency