Android working with ViewPager2, TabLayout and Page Transformers

As we all know, the Android team is constantly releasing new updates and improvements to the Android Framework. One of the components that received major updates is ViewPager2. ViewPager2 is the replacement of ViewPager and got few performance improvements and additional functionalities. In order to use ViewPager2, you should consider using androidx artifacts in your project.
In my earlier tutorial, I have explained Building Intro Sliders to your App using ViewPager. In this article, we are going to try the same but using ViewPager2. We’ll also go through the additional interesting functionalities provided by ViewPager2.
Whats’s New in ViewPager2
- ViewPager2 is improvised version of ViewPager that provides additional functionalities and addresses common issues faced in ViewPager.
- ViewPager2 is built on top of RecyclerView. So you will have great advantages that a RecyclerView has. For example, you can take advantage of DiffUtils to efficiently calculate the difference between data sets and update the ViewPager with animations.
- ViewPager2 supports vertical orientation. Earlier vertical swiping is done by customizing the ViewPager.
- ViewPager2 has right-to-left(RTL) support and this will be enabled automatically based on app locale.
- When working with a collection of Fragments, calling notifyDatasetChanged() will update the UI properly when an underlying Fragment changes its UI.
- ViewPager2 supports page transformations i.e you can provide animations when switching between pages. You can also write your own custom page transformation.
- PagerAdapter is replaced by RecyclerView.Adapter as its based on RecyclerView.
- FragmentStatePagerAdapter is replaced by FragmentStateAdapter.
To get started with ViewPager2, add the dependency to app/build.gradle.
implementation "androidx.viewpager2:viewpager2:1.0.0"
1. ViewPager with Static Views
Usually, ViewPager is used to achieve a tabbed view by combining the TabLayout and collection of Fragments. But if you want to have static views without the Fragment class, you can do it using RecyclerView adapter class.
Below is an example of implementing Intro Slides using ViewPager2. The designs are taken from my older example How to Build Intro Slider for your App but the implementation part varies due to changes in ViewPager2 and in adapter class.
Add the ViewPager2 to your layout file. You can see namespace is uses androidx package androidx.viewpager2.widget.ViewPager2.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto".../> <androidx.viewpager2.widget.ViewPager2 android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="match_parent" /> <RelativeLayout/>
public class ViewsSliderActivity extends AppCompatActivity { private ViewsSliderAdapter mAdapter; private TextView[] dots; private int[] layouts; private ActivityViewsSliderBinding binding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = ActivityViewsSliderBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); init(); } private void init() { // layouts of all welcome sliders // add few more layouts if you want layouts = new int[]{ R.layout.slide_one, R.layout.slide_two, R.layout.slide_three, R.layout.slide_four}; mAdapter = new ViewsSliderAdapter(); binding.viewPager.setAdapter(mAdapter); binding.viewPager.registerOnPageChangeCallback(pageChangeCallback); binding.btnSkip.setOnClickListener(v -> launchHomeScreen()); binding.btnNext.setOnClickListener(v -> { // checking for last page // if last page home screen will be launched int current = getItem(+1); if (current < layouts.length) { // move to next screen binding.viewPager.setCurrentItem(current); } else { launchHomeScreen(); } }); binding.iconMore.setOnClickListener(view -> { showMenu(view); }); // adding bottom dots addBottomDots(0); } /* * Adds bottom dots indicator * */ private void addBottomDots(int currentPage) { dots = new TextView[layouts.length]; int[] colorsActive = getResources().getIntArray(R.array.array_dot_active); int[] colorsInactive = getResources().getIntArray(R.array.array_dot_inactive); binding.layoutDots.removeAllViews(); for (int i = 0; i < dots.length; i++) { dots[i] = new TextView(this); dots[i].setText(Html.fromHtml("•")); dots[i].setTextSize(35); dots[i].setTextColor(colorsInactive[currentPage]); binding.layoutDots.addView(dots[i]); } if (dots.length > 0) dots[currentPage].setTextColor(colorsActive[currentPage]); } private int getItem(int i) { return binding.viewPager.getCurrentItem() + i; } private void launchHomeScreen() { Toast.makeText(this, R.string.slides_ended, Toast.LENGTH_LONG).show(); finish(); } private void showMenu(View view) { PopupMenu popup = new PopupMenu(this, view); MenuInflater inflater = popup.getMenuInflater(); inflater.inflate(R.menu.pager_transformers, popup.getMenu()); popup.setOnMenuItemClickListener(item -> { if (item.getItemId() == R.id.action_orientation) { binding.viewPager.setOrientation(ViewPager2.ORIENTATION_VERTICAL); } else { binding.viewPager.setPageTransformer(Utils.getTransformer(item.getItemId())); binding.viewPager.setCurrentItem(0); binding.viewPager.getAdapter().notifyDataSetChanged(); } return false; }); popup.show(); } /* * ViewPager page change listener */ ViewPager2.OnPageChangeCallback pageChangeCallback = new ViewPager2.OnPageChangeCallback() { @Override public void onPageSelected(int position) { super.onPageSelected(position); addBottomDots(position); // changing the next button text 'NEXT' / 'GOT IT' if (position == layouts.length - 1) { // last page. make button text to GOT IT binding.btnNext.setText(getString(R.string.start)); binding.btnSkip.setVisibility(View.GONE); } else { // still pages are left binding.btnNext.setText(getString(R.string.next)); binding.btnSkip.setVisibility(View.VISIBLE); } } }; public class ViewsSliderAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { public ViewsSliderAdapter() { } @NonNull @Override public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()) .inflate(viewType, parent, false); return new SliderViewHolder(view); } @Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { } @Override public int getItemViewType(int position) { return layouts[position]; } @Override public int getItemCount() { return layouts.length; } public class SliderViewHolder extends RecyclerView.ViewHolder { public TextView title, year, genre; public SliderViewHolder(View view) { super(view); } } } }
This creates horizontally swipeable views that are created using static XML layouts. The full code of this example can be found here.

2. ViewPager with Tabs & Fragments
If you want to create swipeable views with Tabs, you can combine ViewPager2, TabLayout and Fragments.
To use TabLayout, add Material Components to your package. This makes the material TabLayout available in your project.
implementation 'com.google.android.material:material:1.2.0-alpha01'
Add TabLayout and ViewPage2 to your layout.
Create required test Fragment classes MoviesFragment, EventsFragment and TicketsFragment.
import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import androidx.fragment.app.Fragment; import info.androidhive.viewpager2.R; public class MoviesFragment extends Fragment { @Override public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState ) { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_movies, container, false); } }
Finally, create an adapter class that provides Fragments to ViewPager. Here we can see ViewPagerFragmentAdapter extends FragmentStateAdapter.

3. ViewPager2 Orientation
In a few scenarios, you might want to provide vertical swiping instead of traditional horizontal swiping. To enable vertical swiping, add android:orientation to ViewPager2 element.
<androidx.viewpager2.widget.ViewPager2 android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" />
Vertical orientation can also be enabled programmatically by calling setOrientation() method.
viewPager.setOrientation(ViewPager2.ORIENTATION_VERTICAL);
4. ViewPager Transformers
Another great feature of ViewPager2 is, page transformations i.e the page transition animation from one page to another. Traditionally, we see a sliding animation between two screens. This animation can be customized by providing page transformers to ViewPage2.
To set a custom transformation, use setPageTransformer() method. Below example creates Flip animation between pages.
package info.androidhive.viewpager2.transformers; import android.view.View; import androidx.viewpager2.widget.ViewPager2; public class HorizontalFlipTransformation implements ViewPager2.PageTransformer { @Override public void transformPage(View page, float position) { page.setTranslationX(-position * page.getWidth()); page.setCameraDistance(12000); if (position < 0.5 && position > -0.5) { page.setVisibility(View.VISIBLE); } else { page.setVisibility(View.INVISIBLE); } if (position < -1) { // [-Infinity,-1) page.setAlpha(0); } else if (position <= 0) { // [-1,0] page.setAlpha(1); page.setRotationY(180 * (1 - Math.abs(position) + 1)); } else if (position <= 1) { // (0,1] page.setAlpha(1); page.setRotationY(-180 * (1 - Math.abs(position) + 1)); } else { page.setAlpha(0); } } }
This creates beautiful vertical flip animation when swiping the pages.

Below are a set of ViewPager transitions that I have collected from different sources (All the credits goes to original authors).
- Anti Clock Spin Transformation
- Clock Spin Transformation
- Cube In Depth Transformation
- Cube In Rotation Transformation
- Cube In Scaling Transformation
- Cube Out Depth Transformation
- Cube Out Rotation Transformation
- Cube Out Scaling Transformation
- Depth Page Transformer
- Depth Transformation
- Fade Out Transformation
- Fan Transformation
- Fidget Spin Transformation
- Gate Transformation
- Horizontal FlipTransformation
- Pop Transformation
- Spinner Transformation
- Toss Transformation
- Vertical Flip Transformation
- Vertical Shut Transformation
- Zoom Out Page Transformer
Transformations References:
Viewpager-Transformation
Loginworks
Hi there! I am Founder at androidhive and programming enthusiast. My skills includes Android, iOS, PHP, Ruby on Rails and lot more. If you have any idea that you would want me to develop? Let’s talk: [email protected]