Exploring the View Pager 2

It’s likely when working in the Android realm you’ve come across the ViewPager class at some point. This view allows us display a collection of fragments or views to display to the user in a swipe-able format – especially popular within on-boarding and content display screens. This component has been with us in the Android world for some time, it was even ported to the androidx libraries – but now we have a newer version of this component, the View Pager 2, which has recently seen an alpha release go out live. Let’s take a look into exactly what’s so different about this iteration.


In some cases, to the user, each of these view pager components would likely feel the same. A view is showed, another one is swiped in view and so on. But about in cases where we may want to show many instances of the same view within a single view-pager… even though if view instances are used, we’re still going to be hit with some inefficiencies. This is where a key difference of the View Pager 2 comes in – what makes this so different is the utilisation of a RecyclerView. This means that just like how we are already showing streams of content using a Recycler View, having our views recycled as we go now allows us to able to utilise exactly the same behaviour when it comes to the View Pager. This in my opinion is huge news and will not only give our users a smoother experience, but it will also make it easier for us as developers to implement this component.

Other features of the recycler view also become available at this point – if you’ve made use of the DiffUtil functionality then you know just how powerful that can be. Because we’re now making use of the RecyclerView we’ll now be able to perform diffing operations using this class, being more efficient when it comes to handling dynamic or updating content in our view pager component.

We also have other features that are now being introduced with the View Pager 2 – Right-to-Left support and Vertical orientation being two more of them. This gives us the ability to create more inclusive applications as well as utilise this component for specific screen designs.

And don’t worry, just because we’re using a recycler view it doesn’t mean we can’t still use fragments. We can make use of the FragmentStateAdapter to handle our fragments within the view pager 2 – this replaces the FragmentStatePagerAdapter and will make it much clearer how to handle fragments in this component moving forward.

And as a side note, it’s going to be much easier for the Android team to maintain. Not only is the recycler view now promoting and experiencing re-use, but the View pager class has dropped from 3169 lines of code to 583. If you ever dived into the source of the View Pager then you might remember there being a lot of complexities – edge detection, gesture detections, state persistence, calculations for offsets and positioning, drawing of margins, view drawing and a lot of custom calculations. Removing the need to maintain a class with its own logic for a sole purpose will be a great win for the team.


Under the hood

When working with components, it can often be helpful to have a good understanding of what is going on under the hood. Not only does this help you to understand what the component is capable of, but when it comes to bugs you’ll have better knowledge to address issues which occur. Just like the View Pager, the View Pager 2 extends from the View Group class – from there, things look a little different. With some omissions, this is what the core of the View Pager 2 is made up of:

 

vp2

Recycler View

The View Pager 2 uses the RecyclerView component to handle the display of content that you assign to it. This brings us many advantages which I’ve already outlined in this post. – but essentially this now means that we can make use of most of the Recycler View components that we are already familiar with.

Layout manager

This is exactly the same LayoutManager class that you would have previously used with the RecyclerView component in your apps. The layout manager is managed by the View Pager so that the developer has the ability to set the orientation on the component. Whilst you don’t have any control over what layout manager is used (a LinearLayoutManager is what is automatically assigned), you can set the the orientation to be used by the manager. Using the setOrientation() function on our view pager 2, we can pass in an orientation value which will allow us to set the orientation for the layout manager. The original view pager only offered as horizontal orientation, so for apps displaying paged content in a vertical manner will find great use in this.

Page Change Callback

You can register a page change callback (in the form of the OnPageChangeCallback class) on our view pager 2. 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

Adapter

Just like we’d set an adapter for our RecyclerView components elsewhere, we now can do the same for the ViewPager. This is no different from how we are used to working with the RecyclerView adapter.

Pager Snap Helper

This isn’t something we can configure – but I wanted to point out its usage as it’s something that differs from the original view pager. Here, the PagerSnapHelper class is used by the ViewPager to simulate snapping to the selected item when the scroll position requirements for that item are met. You may have used this class before in your own RecyclerView, but this shows the reuse of already components to improve something within the framework.

Feb-21-2019 12-42-56


As well as the functions mentioned above, we still have access to other parts that we may be familiar with from the original View Pager. These are things such as:

  • setCurrentItem() –  Sets the current item that should be shown on the screen
  • getCurrentItem() – Get the current item index for the item shown on the screen
  • setPageTransformer() -Set a transformer to apply custom transformations when page changes occur

 

Implementing the View Pager

To add the View Pager 2 into our project we need to begin by adding the required dependency to our build.gradle file:

implementation 'androidx.viewpager2:viewpager2:1.0.0-alpha01'

With that added, we now have access to the View Pager 2 component, which means we can go ahead and add it to our layout file:

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

Now that we have the View Pager defined in our layout, we need to assign it some data to display on screen to the user by creating an adapter that extends from the RecyclerView.Adapter class. We can then assign this adapter to our view pager instance:

val adapter = WelcomeAdapter()
adapter.welcomeItems = listOf(WelcomeItem.WELCOME_ONE, WelcomeItem.WELCOME_TWO, WelcomeItem.WELCOME_THREE)
view_pager.adapter = adapter

Now that we have content displaying, we may want to tweak the orientation of the view pager. By default, the view pager uses the horizontal orientation:

androidx.viewpager2.widget.ViewPager2.ORIENTATION_HORIZONTAL

Feb-21-2019 12-45-59

You won’t need to change anything here if this is the desired orientation. However, if you wish to make use of vertical orientation then you can change this by calling setOrientation() and passing in the ORIENTATION_VERTICAL value:

view_pager.orientation = ORIENTATION_VERTICAL

Feb-21-2019 12-46-39

We can also listen for events from the view pager as we may wish to adapt our UI or data based on the pages that the user selects. Again, here we can observe onPageScrolled(), onPageSelected() and onPageScrollStateChanged():

view_pager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {

   // override desired callback functions

})

 

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. You can check the documentation for using the DiffUtil here, but as an example lets say we had the content shown in the above GiIFs as our data set. If we then performed a DiffUtil operation with the same data where only the title of the last screen was different, we would be able to make use of the change payload from the diff result to only update that piece of content – which is much more efficient when it comes to dynamic content within view pager components.


I hope this has given you an insight into the new View Pager component and what we are able to achieve as a result of its usage. Whilst it is still in alpha, it promise a more efficient approach to the display and management of our content – which in turn will result in a better experience for our users. Combined with the DiffUtil and other features backed by the recycler view (animations etc), the View Pager 2 promises an improved experienced in both implementation and usage. Are you using the View Pager currently, how will you make use of the View Pager 2? Let me know in the comment section below 🙌