Exploring ViewPager2 in Android

ViewPager2 in Android allows the user to flip left and right through pages of data. In our android ViewPager2 application we’ll implement a ViewPager2 that swipes through four views with different background colors and texts.

Following are the features that ViewPager2 brings to us

  • Right to Left Layout Support
  • Vertical Orientation
  • Use of RecyclerView implicitly
  • Shift from PagerAdapter to RecyclerView.Adapter
  • Better control of Animation on Page change
  • A Better PageChangeListener
  • A working notifyDataSetChanged

We can also perform DiffUtil operations on our data to dynamically update the content within our View Pager, this means we don’t need to reload and set the entire data set — only the data that has changed.

What has been changed!

  • PagerAdapter is replaced by RecyclerView.Adapter.
  • FragmentStatePagerAdapter is replaced by FragmentStateAdapter.

This version of ViewPager2 is released for Android X so if you want to use it then your project must have been migrated to Android X. Let’s see how we can use this new ViewPager2.

Developers familiar with the RecyclerView will have no trouble adopting the new ViewPager2 APIs. While the ViewPager2 extends from a ViewGroup, it carriers a RecyclerView under the hood. To provide data to the view, find the ViewPager2 in your layout and set the adapter.

Add following dependency to your app level build.gradle file:

dependencies {    
    implementation "androidx.viewpager2:viewpager2:1.0.0-beta02"
}

Add ViewPager2 widget to your Activity/Fragment.

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

Let’s create a layout for our page representation. Following is a content for item_page.xml

<?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:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/tvTitle"
        android:textColor="@android:color/white"
        android:layout_width="wrap_content"
        android:layout_centerInParent="true"
        tools:text= "item"
        android:textSize="32sp"
        android:layout_height="wrap_content" />

</RelativeLayout>

Next, we need to create Adapter for ViewPager2. For this we can use RecyclerView.Adapter. Following is a content for ViewPagerAdapter.kt

class ViewPagerAdapter : RecyclerView.Adapter<ViewPagerAdapter.PagerVH>() {
    private val colors =  intArrayOf(android.R.color.black,
        android.R.color.holo_red_light,
        android.R.color.holo_blue_dark,
        android.R.color.holo_purple
    )

    inner class PagerVH(itemView: View) : RecyclerView.ViewHolder(itemView) {

    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PagerVH 
        = PagerVH(LayoutInflater.from(parent.context).inflate(R.layout.item_page, parent, false))

    override fun getItemCount(): Int = colors.size

    override fun onBindViewHolder(holder: PagerVH, position: Int) = holder.itemView.run {
        tvTitle.text = "item $position"
        container.setBackgroundResource(colors[position])

    }
}

Finally, set adapter for ViewPager2.

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        viewPager2.adapter = ViewPagerAdapter()
    }
}

Vertical Scrolling

With this new ViewPager2, we have in house support for vertical scrolling. Just set orientation to ViewPager2 and vertical scrolling will be enabled for you!

viewPager2.orientation = ViewPager2.ORIENTATION_VERTICAL

Using FragmentStateAdapter

You can use fragments too as you would with the old ViewPager. For that, we have FragmentStateAdapter. Let’s see how we can use this. First of all, we need to create a fragment:

class PagerFragment : Fragment() {
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.item_page, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        arguments?.let {    
            container.setBackgroundResource(it.getInt("color"))
            tvTitle.text = "Item ${it.getInt("position")}"        
        }

    }
}

Now we’ll create Adapter for ViewPager2. It will take FragmentManager as constructor argument to manage fragments.

class ViewPagerFragmentStateAdapter(fm: FragmentManager) : FragmentStateAdapter(fm) {
    private val colors = intArrayOf(
        android.R.color.black,
        android.R.color.holo_red_light,
        android.R.color.holo_blue_dark,
        android.R.color.holo_purple
    )

    override fun getItem(position: Int): Fragment = PagerFragment().apply {
        arguments = bundleOf(
            "color" to colors[position],
            "position" to position
        )
    }

    override fun getItemCount(): Int = colors.size
}

That’s it! set this new adapter to viewPage2 and you’re good to go.

viewPager2.adapter = ViewPagerFragmentStateAdapter(supportFragmentManager)

Page Change Callback

You can register a page change callback (in the form of the OnPageChangeCallback class) on our ViewPager2. This will allow you to listen for changes on the selected page. Within this callback we can listen for:

  • onPageScrolled() — Triggered when a scroll event occurs for the current page
  • onPageSelected() — Triggered when a new page becomes selected
  • onPageScrollStateChanged() — Triggered when the scroll state changes

OnPageChangeCallback abstract class means that we don’t need to override all these methods, we can just override the ones we care or we willing to use.

viewPager2.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
    override fun onPageSelected(position: Int) {
        super.onPageSelected(position)
        Log.d(TAG, "onPageSelected")
    }
})

Other

Scroll to page programatically viewPager2.currentItem = PAGE or viewPager2.setCurrentItem(position, true) (with Animation).

Disable user scroll: viewPager2.isUserInputEnabled = false.

You can link TabLayout and viewPager2 as described here.