If you can't learn, you have to learn! What's new in ViewPager2

preface

When browsing the official website of Android developers two days ago, I found that Google had quietly launched a new control: ViewPager2, Nani??? This is the upgraded version of ViewPager from the name. After looking at the time of launching this control, Google has released it as early as February 7, 2019, and then carried out a wave of iterative updates, which was officially released on November 20, 2019; It can be related to Jetpack launched by Google in 2018, which aims to help developers easily build more stable, robust and maintainable Android development ecological solutions. It can be imagined that the launch of ViewPager2 is another great addition to the highly expected Jetpack family bucket;
Since it is an upgraded version, what new functions and features does it have compared with ViewPager?
Let's move on.

New features of android ViewPager2

  • Based on RecyclewView. This means that ViewPager2 will inherit the advantages of RecyclewView and fully support the related configuration functions of RecyclerView
  • Support vertical sliding. Only one parameter is needed to change the sliding direction;
  • Support to turn off user input and simulate user sliding. Set whether to disable user sliding behavior by setting setUserInputEnabled(); Simulate the user's sliding page through fakeDragBy(float offsetPx);
  • Multiple pagetransformers are supported
  • DiffUtil is supported. Local data refresh and Item animation are realized by adding data sets.
  • Support RTL layout

Compare with ViewPager

What changes have ViewPager2 made compared with ViewPager? The differences are listed below:

  • Use registerOnPageChangeCallback() instead of addPageChangeListener() to listen for page changes

  • Because the class ViewPager2.java is declared as fianl, it cannot be inherited for secondary transformation, but it can be modified by copying a copy

  • Use FragmentStateAdapter instead of FragmentStatePagerAdapter and RecyclerView.Adapter instead of PagerAdapter;

  • offScreenPageLimit new parameters and new experience

Use of Android ViewPager2

ViewPager2 is located under the Android package, that is, it is not built into the system source code like ViewPager. Therefore, using ViewPager2 requires additional dependent libraries.

In addition, ViewPager2 is not included in android support, that is, to use ViewPager2, you must migrate to Android X.

① Add dependency

At present, the latest stable version of ViewPager2 is 1.0.0.

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

② Declare in XML file

    <androidx.viewpager2.widget.ViewPager2
       android:id="@+id/view_pager"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       app:layout_constraintBottom_toBottomOf="parent"
       app:layout_constraintLeft_toLeftOf="parent"
       app:layout_constraintRight_toRightOf="parent"
       app:layout_constraintTop_toTopOf="parent" />

③ Custom Adapter

ViewPager2 is implemented by RecyclerView, so its Adapter is actually the RecyclerView Adapter.

       class MyAdapter extends RecyclerView.Adapter<MyAdapter.PagerViewHolder> {
        private List<Integer> mList;

        public PagerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_page, parent, false);
            return new PagerViewHolder(view);
        }

        @Override
        public void onBindViewHolder(@NonNull PagerViewHolder holder, int position) {
            holder.bindData(position);
        }

        @Override
        public int getItemCount() {
            return mList.size();
        }

        public void setList(List<Integer> list){
            this.mList = list;
        }

        class PagerViewHolder extends RecyclerView.ViewHolder {
            private TextView mTextView = itemView.findViewById(R.id.tv_text);
            private String[] colors = new String[]{"#CCFF99", "#41F1E5", "#8D41F1", "#FF99CC"};

            public PagerViewHolder(@NonNull View itemView) {
                super(itemView);
            }

            private void bindData(int index) {
                mTextView.setText(index);
                mTextView.setBackgroundColor(Color.parseColor(colors[index]));
            }
        }
    }

item_page layout file:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:gravity="center">

      <TextView
        android:id="@+id/tv_text"
        android:background="@color/colorPrimaryDark"
        android:layout_width="match_parent"
        android:layout_height="280dp"
        android:gravity="center"
        android:textColor="#ffffff"
        android:textSize="22sp" />
    </LinearLayout>

④ Binding ViewPager and dispatcher

        ViewPager2 viewPager2 = findViewById(R.id.view_pager);
        MyAdapter myAdapter = new MyAdapter();
        myAdapter.setList(data)
        viewPager2.setAdapter(myAdapter);

Through the above access, you can complete the simple effect of a ViewPager sliding page, as follows;

⑤ Set vertical sliding

Only one line of code is needed to set ViewPager2 to slide vertically:

    viewPager2.setOrientation(ViewPager2.ORIENTATION_VERTICAL); 

For this point, if the previous ViewPager is difficult to achieve, you can see the following effects:

⑥ Page sliding listening event

As mentioned above, viewPager2 only needs to rewrite the method we need to listen to page sliding

       viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
            @Override
            public void onPageSelected(int position) {
                super.onPageSelected(position);
            }
        });

⑦ Prohibit user sliding and simulate user sliding

API involved: setUserInputEnabled() and fakeDragBy().

We know that when using ViewPager, if you want to prevent users from sliding, you need to rewrite the onInterceptTouchEvent() of ViewPager. While ViewPager2 is declared as final, we can no longer inherit ViewPager2.

So how can we disable the sliding of ViewPager2? In fact, this function has been provided for us in ViewPager2, which only needs to be implemented through setUserInputEnabled().

    viewPager2.setUserInputEnabled(false);

At the same time, ViewPager2 adds a method of fakeDragBy(). This method can be used to simulate drag and drop. Before using fakeDragBy(), you need to use the beginFakeDrag() method to enable simulated drag.

fakeDragBy() will return a boolean value:

true indicates that a fake drag is being executed;
false indicates that no make drag is currently executing.
Let's try the following through code:

    private void fakeDragBy(ViewPager2 viewPager2) {
        viewPager2.beginFakeDrag();
        if (viewPager2.fakeDragBy(100f)) {
            viewPager2.endFakeDrag();
        }
    }

It should be noted that fakeDragBy() accepts a float parameter. When the parameter value is positive, it means sliding to the next page, and when the value is negative, it means sliding to the next page.

Let's look at the renderings below:

User input is prohibited in the demonstration diagram, and user sliding can be simulated by clicking the button.

⑧ offScreenPageLimit()

You can also set the preload page parameter in the viewpager, but even if we set 0, the viewpager will be forced to change to, which is criticized by the majority of developers;

This is optimized in ViewPager2, which can be found through the source code:

    # VewPager2
    
    private @OffscreenPageLimit int mOffscreenPageLimit = OFFSCREEN_PAGE_LIMIT_DEFAULT;

    /**
     * Value to indicate that the default caching mechanism of RecyclerView should be used instead
     * of explicitly prefetch and retain pages to either side of the current page.
     * @see #setOffscreenPageLimit(int)
     */
    public static final int OFFSCREEN_PAGE_LIMIT_DEFAULT = -1;

     /** @hide */
    @SuppressWarnings("WeakerAccess")
    @RestrictTo(LIBRARY_GROUP_PREFIX)
    @Retention(SOURCE)
    @IntDef({OFFSCREEN_PAGE_LIMIT_DEFAULT})
    @IntRange(from = 1)
    public @interface OffscreenPageLimit {
    }

You can see that the default number of preloaded pages is set to the default value of - 1, which can be understood here as not performing page preloading; Moreover, if you want to set the number of preloaded pages, you can assign a value by setting the setoffsetscreenpagelimit value. Note that the annotation here is marked as greater than or equal to 1;

    public void setOffscreenPageLimit(@OffscreenPageLimit int limit) {
      if (limit < 1 && limit != OFFSCREEN_PAGE_LIMIT_DEFAULT) {
        throw new IllegalArgumentException(
                "Offscreen page limit must be OFFSCREEN_PAGE_LIMIT_DEFAULT or a number > 0");
      }
      mOffscreenPageLimit = limit;
      // Trigger layout so prefetch happens through getExtraLayoutSize()
      mRecyclerView.requestLayout();
    }

Let's see the different effects of setting different number of moffscreen pagelimit:

First, we add multiple fragments in ViewPager, and setoffsetscreenpagelimit() uses the default value. Then, the log is printed in the Fragment declaration cycle. The code is no longer posted, and you can directly see the contents printed in the log:

You can see that only the first fragment has been initialized. When we slide to the next fragment, look at the log:

You can see that the page starts loading only when you slide to the second fragment; Therefore, when the default value of - 1 is adopted, preload does not occur during sliding

Next, let's change the offscreen pagelimit value to 1 and look at the output log:

At this point, you can see that after the offscreen pagelimit is set to 1, a page will be preloaded, which has almost the same effect as the ViewPager.

In short, ViewPager2 optimizes the Preloading Mechanism of ViewPager to make the experience better.

Seeing here, many people will think, that's it? Does ViewPager2 only have so many functions? Don't worry, the following new dynamic effect is the highlight;

III. PageTransformer

The Transformer function of ViewPager2 is greatly extended compared with ViewPager.

ViewPager2 can not only be used to set page animation through PageTransformer, but also add multiple pagetransformers at the same time. Next, let's take a look at the PageTransformer of ViewPager2!

First, let's introduce the composite page transformer

As can be seen from the name, it is a combined PageTransformer. In fact, CompositePageTransformer implements the interface of PageTransformer and internally maintains a List set of PageTransformer;

So let's see how to use this compositepage transformer

   CompositePageTransformer compositePageTransformer = new CompositePageTransformer();
   compositePageTransformer.addTransformer(new ScaleInTransformer());
   compositePageTransformer.addTransformer(new MarginPageTransformer(10));
   viewPager2.setPageTransformer(compositePageTransformer);

In the above code, we set a ScaleInTransformer with custom page scaling and a MarginPageTransformer with page margins for the CompositePageTransformer. You can see the following effects:

The ScaleInTransformer code for customizing page scaling is as follows:

    class ScaleInTransformer implements ViewPager2.PageTransformer {
        static final float DEFAULT_MIN_SCALE = 0.85f;
        static final float DEFAULT_CENTER = 0.5f;

        @Override
        public void transformPage(@NonNull View view, float position) {
            view.setElevation(-abs(position));
            int pageWidth = view.getWidth();
            int pageHeight = view.getHeight();

            view.setPivotY((pageHeight / 2));
            view.setPivotX((pageWidth / 2));
            if (position < -1) {
                view.setScaleX(DEFAULT_MIN_SCALE);
                view.setScaleY(DEFAULT_MIN_SCALE);
                view.setPivotX(pageWidth);
            } else if (position <= 1) {
                if (position < 0) {
                    float scaleFactor = (1 + position) * (1 - DEFAULT_MIN_SCALE) + DEFAULT_MIN_SCALE;
                    view.setScaleX(scaleFactor);
                    view.setScaleY(scaleFactor);
                    view.setPivotX(pageWidth * (DEFAULT_CENTER + DEFAULT_CENTER * -position));
                } else {
                    float scaleFactor = (1 - position) * (1 - DEFAULT_MIN_SCALE) + DEFAULT_MIN_SCALE;
                    view.setScaleX(scaleFactor);
                    view.setScaleY(scaleFactor);
                    view.setPivotX(pageWidth * ((1 - position) * DEFAULT_CENTER));
                }
            } else {
                view.setPivotX(0f);
                view.setScaleX(DEFAULT_MIN_SCALE);
                view.setScaleY(DEFAULT_MIN_SCALE);
            }
        }
    }

Implementation of viewpager2 with one screen and multiple pages

Check the official google Documents. You can see that the official implementation of multiple pages on one screen is realized by setting padding for recyclerview. The code is as follows:

        RecyclerView recyclerView = (RecyclerView) viewPager2.getChildAt(0);
        int padding = 20;
        recyclerView.setPadding(padding, 0, padding, 0);
        recyclerView.setClipToPadding(false);

        CompositePageTransformer compositePageTransformer = new CompositePageTransformer();
        compositePageTransformer.addTransformer(new ScaleInTransformer());
        compositePageTransformer.addTransformer(new MarginPageTransformer(10));
        viewPager2.setPageTransformer(compositePageTransformer);

Finally, let's look at the effect:

4, How to use ViewPager2 in Fragment

As mentioned above, the original FragmentStatePagerAdapter is replaced by the FragmentStatePagerAdapter in ViewPager2. Next, let's see how to use ViewPager2 with Fragment

4.1 add ViewPager2 to XML layout file

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

4.2 implementation of FragmentStateAdapter

The best way to use the FragmentStateAdapter is to customize an Adapter. Let's look at the following code:

    class CustomAdapterFragmentPager extends FragmentStateAdapter {

        final int PAGE_HOME = 0;
        final int PAGE_FIND = 1;
        final int PAGE_INDICATOR = 2;
        final int PAGE_OTHERS = 3;

        public CustomAdapterFragmentPager(@NonNull FragmentActivity fragmentActivity) {
            super(fragmentActivity);
        }

        @NonNull
        @Override
        public Fragment createFragment(int position) {
            switch (position) {
                case PAGE_HOME:
                    return HomeFragment.getInstance();
                case PAGE_FIND:
                    return PageFragment.getInstance();
                case PAGE_INDICATOR:
                    return IndicatorFragment.getInstance();
                case PAGE_OTHERS:
                    return OthersFragment.getInstance();
                default:
                    return EmptyFragment.getInstance();
            }
        }

        @Override
        public int getItemCount() {
            return 4;
        }
    }

The above code overrides the createFragment and getItemCount methods. You can see that it is similar to what the FragmentStatePagerAdapter does;

4.3 ViewPager2 setting FragmentStateAdapter

After initializing ViewPager2 and FragmentStateAdapter, the last step is to set the adapter for ViewPager. The code is as follows:

        viewPager2.setAdapter(new CustomAdapterFragmentPager(this));
        viewPager2.setOffscreenPageLimit(3);
        viewPager2.setUserInputEnabled(false);

5, TabLayout and ViewPager2

TabLayout often appears in development work at ordinary times and is often used with ViewPager. How to use ViewPager2 in TabLayout?

Unlike the original ViewPager, you cannot set vp directly through setViewPager; A control TabLayoutMediator needs to be used in ViewPager2. This class is a new class in material-1.2.0. At present, the latest version of material package is 1.2.0-alpha03. The added dependencies are as follows:

    implementation 'com.google.android.material:material:1.2.0-alpha03'

Three parameters need to be passed in to construct TabLayoutMediator. The first parameter is tablayout; The second parameter is ViewPager2; The third parameter is TabConfigurationStrategy, which is an interface. It needs to implement a method, onConfigureTab(@NonNull TabLayout.Tab tab, int position). The first parameter is the current tablayout and the second is the current position:

    public interface TabConfigurationStrategy {
      /**
       * Called to configure the tab for the page at the specified position. Typically calls {@link
       * TabLayout.Tab#setText(CharSequence)}, but any form of styling can be applied.
       *
       * @param tab The Tab which should be configured to represent the title of the item at the given
       *     position in the data set.
       * @param position The position of the item within the adapter's data set.
       */
      void onConfigureTab(@NonNull TabLayout.Tab tab, int position);
    }

By constructing TabLayoutMediator, we can use tablayout and viewpage2 together:

    new TabLayoutMediator(tabLayout, viewPager2, new TabLayoutMediator.TabConfigurationStrategy() {
         @Override
         public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
            tab.setText(titles[position]);
        }
    });

Finally, let's look at the renderings:

6, Summary

In the above article, I led you to understand the new features of ViewPager2 and the differences between ViewPager2 and ViewPager in development and use;
It can be seen that ViewPager2 is far ahead of ViewPager in terms of API, performance and dynamic effect, so I think there is a great probability that it will replace the original ViewPager in the future;

After reading this, it's time to connect ViewPager2 to your project!

Reference article:
https://www.jianshu.com/p/bd70970600aa​

❤️ Thank you for your support

The above is all the content of this sharing. I hope it will help you_

If you like it, don't forget to share, like and collect three times ~.

Welcome to the official account bus programmer, an interesting, fan, and temperature programmer bus, and browse the contents of the factory, programmer's life, practical course, technology frontier, etc., pay attention to me and make friends.

Tags: Android viewpager

Posted on Thu, 07 Oct 2021 15:48:01 -0400 by pillot1005