Android ViewPager2 & TabLayout
ViewPager2 is introduced in this year 2019 Google I/O and is a replacement of the old ViewPager, which was created in 2011. It includes some new features to enhance UI and coding experience, including:
- Right-to-left layout support
- Vertical orientation (Scroll vertically)
- modifiable Fragment collections
ViewPager2
is a ViewGroup
backed by a RecyclerView
and thus the handling method is similar to that for RecyclerView
. ViewPager2
requires an adapter to show its contents and the adapter can be either RecyclerView adapter
or FragmentStateAdapter
.
This article will cover the basic handling of ViewPager2
and the linking with a TabLayout
. If you have been familiar with the setup of ViewPager2
, you could jump to “Trick” session directly.
Setup
ViewPager2
is packed inside the latest AndroidX library of JetPack
instead of Material Component library
. Thus, we have to import it separately with the following gradle code:
Bear in mind that
AndroidX library
should not be kept togethersupport library
to prevent any unexpected results.
XML layout
Simply add ViewPager2
widget to your layout:
Define a RecyclerView adapter and cell layout for ViewPager2
Bind RecyclerView adapter with ViewPager2
The method to set an adapter to ViewPager2 is
Simple result:
Trick — TabLayout
cannot be bound with ViewPager2
In the current release of Material Component
library (version: 1.1.0-alpha06), TabLayout
widget is not yet ready to bind with a ViewPager2
widget natively. So, how do we work around with it? According to Nikola Despotoski’s answer in StackOverflow, we can manually use the class TabLayoutMediator to bind a TabLayout
widget with a ViewPager2
.
However, according to the source code, TabLayoutMediator
is restricted to library level and cannot be called directly from developer’s code. Therefore, we have to make a copy of this file to our project and call it locally. According to the comments in source code, attach()
can only be called after TabLayoutMediator
is initialised.
The TabLayoutMediator.OnConfigureTabCallback
is a user friendly function which is called when eachTabLayout.Tab
is initialised or data are changed. It exposes the opportunity to style all the tabs.
Final result:
RecyclerView adapter Vs FragmentStateAdapter
As mentioned at the start of the article, ViewPager2
accepts both RecyclerView.Adapter
and FragmentStateAdapter
.
FragmentStateAdapter
is a direct child of RecyclerView.Adapter
. The main difference between them is that RecyclerView.Adapter
inflates View
but FragmentStateAdapter
inflates Fragment
.
Thus, RecyclerView.Adapter
can be used when each page in ViewPager2
is made for displaying static information only, andFragmentStateAdapter
can be used when lifecycle of each page has to be taken into consideration.
For example, photo viewer ViewPager can use RecyclerView.Adapter
to display a list of images, and application form pages with EditText
can use FragmentStateAdapter
to use onSaveInstanceState()
in each Fragment
if necessary.
Integration with TabLayout
It was simple to integrate a TabLayout
with the old version of ViewPager
by simply add it as a child of ViewPager
and position by XML property android:layout_gravity
. See this Google documentation.
<android.support.v4.view.ViewPager
android:layout_width="match_parent"
android:layout_height="match_parent"> <android.support.design.widget.TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top" /> </android.support.v4.view.ViewPager>
However, ViewPager2
(version 1.0.0-alpha04) does not support direct child views which means that TabLayout
cannot be added to ViewPager2 as a ViewPager.DecorView. TabLayout
has to be placed inside a FrameLayout
together with ViewPager2
in order to achieve the same effect.
As the comment written in the above function, Google probably would include back the feature of supporting direct child views in the next or stable version of ViewPager2
in the future.
Conclusion:
ViewPager2
includesRecycleView
to originalViewPager
and makes the coding much easier than before.ViewPager2
(version1.0.0-alpha04
) is not available to be bound by aTabLayout
natively .TabLayoutMediator
is a good work around for this issue.ViewPager2
requires an adapter to control the content in each page. It can be eitherRecyclerView.Adapter
orFragmentStateAdapter
.RecyclerView.Adapter
is suitable for static content case andFragmentStateAdapter
is suitable for content which requires to listen to lifecycle event.ViewPager2
is not allowed to have any child views.TabLayout
has to be placed inside anotherViewGroup
together withViewPager2
.
Further readings:
1. It is common to set ViewPager
to have horizontal margin while keeping the previous and next pages visible to user. However, the function is missing in ViewPager2
and caching mechanism is disabled by default. Let’s see how we can fix this issue here.
2. Dot-styled TabItem
is not officially documented. The process is concluded to only 4 simple steps.
3. TabLayout
works closely with ViewPager
and ViewPager2
. However, styling TabLayout
and TabItem
is sometimes confusing. Read the following article if you need.
Please follow me at Twitter@myrick_chow for more information. Thank you for reading this article. Have a nice day! 😄