ViewPager2 instruction manual

Zero, the Demo

Program source code

Demo apk

If it is useful to you, I hope you can give me a STAR. Thank you.

A, functionality,

Creating a sliding view using ViewPager2

Swipe views allow you to navigate between sibling screens, such as tabs, with a horizontal finger gesture, or swipe. This navigation pattern is also referred to as horizontal paging. This topic teaches you how to create a tab layout with swipe views for switching between tabs, along with how to show a title strip instead of tabs.

You can use ViewPager2 to slide Views or pages horizontally (usually horizontal, vertical is also supported). It can also be used with the Tab component.

Two, basic use

2.1 Dependent Reference

implementation "Androidx. Viewpager2: viewpager2:1.0.0."
Copy the code

2.2 Version Description

Version 1.0.0 was updated on November 20, 2019.

Beta version 1.1.0- Beta01 was released on August 4, 2021 and has only recently been updated.

Detailed updates, as well as information on the latest version, can be found at this link.

2.3 Basic Usage

ViewPager2 is simple to use. There are several elements to learn: XML declaration, defining Adapter, and setting up slide listeners.

Used in 2.3.1 XML layout

<androidx.viewpager2.widget.ViewPager2
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
Copy the code

2.3.2 Common Adapter types

ViewPager2.java

private void initialize(Context context, AttributeSet attrs) {
        mAccessibilityProvider = sFeatureEnhancedA11yEnabled
                ? new PageAwareAccessibilityProvider()
                : new BasicAccessibilityProvider();

        mRecyclerView = new RecyclerViewImpl(context);
        mRecyclerView.setId(ViewCompat.generateViewId());
        mRecyclerView.setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS);

        mLayoutManager = new LinearLayoutManagerImpl(context);
        mRecyclerView.setLayoutManager(mLayoutManager);
        mRecyclerView.setScrollingTouchSlop(RecyclerView.TOUCH_SLOP_PAGING);
        setOrientation(context, attrs);

        mRecyclerView.setLayoutParams(
                newViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); mRecyclerView.addOnChildAttachStateChangeListener(enforceChildFillListener()); . }Copy the code

ViewPager2 through the source, you can see that it maintains a RecyclerView, to achieve list view display and sliding control.

So, RecyclerView.Adapter can be used directly for ViewPager2, this should be used in the use of RecyclerView components often.

In addition, ViewPager2 dependency package, also provide FragmentStateAdapter, inherited from recyclerview. Adapter. Mainly used in combination with ViewPager2 and Fragment. The following describes how to use it.

2.3.3 Slide event listening

void registerOnPageChangeCallback(@NonNull OnPageChangeCallback callback)
Copy the code

With this function, you register event listeners for Page changes.

OnPageChangeCallback class source code is as follows:

 public abstract static class OnPageChangeCallback {
        /**
         * This method will be invoked when the current page is scrolled, either as part
         * of a programmatically initiated smooth scroll or a user initiated touch scroll.
         *
         *
         * @paramposition Position index of the first page currently being displayed. * Page position+1 will be visible if positionOffset  is nonzero. *@param positionOffset Value from [0, 1) indicating the offset from the page at position.
         * @param positionOffsetPixels Value in pixels indicating the offset from position.
         */
        public void onPageScrolled(int position, float positionOffset,
                @Px int positionOffsetPixels) {}/**
         * This method will be invoked when a new page becomes selected. Animation is not
         * necessarily complete.
         *
         * @param position Position index of the new selected page.
         */
        public void onPageSelected(int position) {}/**
         * Called when the scroll state changes. Useful for discovering when the user begins
         * dragging, when a fake drag is started, when the pager is automatically settling to the
         * current page, or when it is fully stopped/idle. {@code state} can be one of {@link
         * #SCROLL_STATE_IDLE}, {@link #SCROLL_STATE_DRAGGING} or {@link #SCROLL_STATE_SETTLING}.
         */
        public void onPageScrollStateChanged(@ScrollState int state) {}}Copy the code

There are three callback methods:

  1. OnPageScrolled, returns Page sliding position offset or pixel change.
  2. OnPageSelected, slide page position.
  3. OnPageScrollStateChanged, change of slide state.

Callback from Page to Page

2021- 08 -18 23:28:14.046  onPageSelected() called with: position = 0
2021- 08 -18 23:28:14.047  onPageScrolled() called with: position = 0, positionOffset = 0.0, positionOffsetPixels = 0
2021- 08 -18 23:28:37.333  onPageScrollStateChanged() called with: state = 1
2021- 08 -18 23:28:37.350  onPageScrolled() called with: position = 0, positionOffset = 0.016666668, positionOffsetPixels = 18.2021- 08 -18 23:28:37.427  onPageScrolled() called with: position = 0, positionOffset = 0.20277777, positionOffsetPixels = 219
2021- 08 -18 23:28:37.431  onPageScrollStateChanged() called with: state = 2
2021- 08 -18 23:28:37.450  onPageSelected() called with: position = 1
2021- 08 -18 23:28:37.451  onPageScrolled() called with: position = 0, positionOffset = 0.28611112, positionOffsetPixels = 309.2021- 08 -18 23:28:37.717  onPageScrolled() called with: position = 0, positionOffset = 0.99814814, positionOffsetPixels = 1078
2021- 08 -18 23:28:37.734  onPageScrolled() called with: position = 1, positionOffset = 0.0, positionOffsetPixels = 0
2021- 08 -18 23:28:37.734  onPageScrollStateChanged() called with: state = 0
Copy the code
OnPageScrollStateChanged Sliding State state: SCROLL_STATE_IDLE = 0 SCROLL_STATE_DRAGGING = 1 SCROLL_STATE_SETTLING = 2Copy the code

Observing the log, the characteristics of the callback:

  1. OnPageSelected and onPageScrolled methods are called back to position 0.
  2. When you swipe a page to the right, the onPageScrollStateChanged callback is first triggered with state as SCROLL_STATE_DRAGGING. OnPageScrolled is then called back several times to see the change in position offset. In the middle of onPageScrolled callbacks, the onPageScrollStateChanged method is called back, and state becomes scroll_STATE_settable. Then call onPageSelected, position to slide position.
  3. Last onPageScrolled callback, position changes to 1. After the onPageScrollStateChanged callback, state changes to SCROLL_STATE_IDLE.

Three, the way of use

3.1 + View

3.1.1 Effect demonstration

3.1.2 Adapter code implementation

Start by defining an Item XML layout.

<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/black"
        android:layout_width="match_parent"
        android:layout_height="280dp"
        android:gravity="center"
        android:textColor="#ffffff"
        android:textSize="22sp" />
</LinearLayout>
Copy the code

Customize the ViewAdapter.

import android.graphics.Color
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView

class ViewAdapter : RecyclerView.Adapter<ViewAdapter.PagerViewHolder>() {
    var data: List<Int> = ArrayList()

    class PagerViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        private val mTextView: TextView = itemView.findViewById(R.id.tv_text)
        private val colors = arrayOf("#CCFF99"."#41F1E5"."#8D41F1"."#FF99CC")

        fun bindData(i: Int) {
            mTextView.text = i.toString()
            mTextView.setBackgroundColor(Color.parseColor(colors[i]))
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PagerViewHolder {
        return PagerViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_page, parent, false))}override fun onBindViewHolder(holder: PagerViewHolder, position: Int) {
        holder.bindData(position)
    }

    override fun getItemCount(a): Int {
        return data.size
    }
}
Copy the code

3.1.3 ViewPager2 configuration

Layout files in an Activity or Fragment directly using the ViewPager2 tag.

Then in the code, the Adapter is configured to achieve the effect of 3.1.1.

    val viewAdapter = ViewAdapter()
    viewAdapter.data = listOf(1.2.3.4)
    viewPager2 = findViewById(R.id.view_pager)
    viewPager2.apply {
      adapter = viewAdapter
    }
Copy the code

3.1.4 Application Scenarios

Banner advertisement. Can cooperate with timer, timing rolling display.

3.2 + fragments

3.2.1 Effect Display

The overall effect, looks like the use of RecyclerView.Aadapter + Views form.

The former is a local control that works with fragments and is more of a whole page slide.

In this example, some animation effects were added, as well as one screen and multiple pages, which will be explained in more detail below.

3.2.2 Adapter code implementation

ViewPager2 is used in conjunction with fragments. As mentioned earlier in Adapter, ViewPager2’s dependencies include a FragmentStateAdapter.

It’s easy to use, just override two methods: getItemCount and createFragment. The following is an example:

TestFragment is a template BlankFragment generated by AndroidStudio with two input parameters, one for the text content of the page and the other for the background color.

import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter

class FragmentPagerAdapter(fragmentActivity: FragmentActivity) :
    FragmentStateAdapter(fragmentActivity) {

    override fun getItemCount(a): Int {
        return 4
    }

    private val colors = arrayOf("#CCFF99"."#41F1E5"."#8D41F1"."#FF99CC")

    override fun createFragment(position: Int): Fragment {
        return when (position) {
            PAGE_MESSAGE -> TestFragment.newInstance("The message$position", colors[0])
            PAGE_CONTACT -> TestFragment.newInstance("The address book$position", colors[1])
            PAGE_SETTING -> TestFragment.newInstance("Setting$position", colors[2])
            PAGE_MINE -> TestFragment.newInstance("I'm$position", colors[3])
            else -> TestFragment.newInstance("$position", colors[0])}}companion object {
        const val PAGE_MESSAGE = 0
        const val PAGE_CONTACT = 1
        const val PAGE_SETTING = 2
        const val PAGE_MINE = 3}}Copy the code

3.2.3 ViewPager2 configuration

It is simple to instantiate the Adapter directly to the Adapter assigned to the ViewPager2 object.

3.2.4 scenario

Switch between pages, support gesture sliding. Support for transition animations.

You can also combine the Tab component to associate components.

3.3 + TabLayout

3.3.1 Effect display

3.3.2 Code implementation

TabLayout is usually placed at the top of the page. In the page layout XML, use com. Google. Android. Material. The tabs. TabLayout label statement.

The TabLayout component is a component in the Material package that Android Studio automatically introduces in new projects.

If you want to introduce TabLayout components in an older version of the project, you can introduce the following dependencies. The specific version is subject to the official website.

'com. Google. Android. Material: material: 1.3.0'
Copy the code

Declare in XML:

    <com.google.android.material.tabs.TabLayout
        android:id="@+id/tab_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
Copy the code

In this code, TabLayout and ViewPager2 are bound via TabLayoutMediator.

      val tabLayout = findViewById<TabLayout>(R.id.tab_layout)
      TabLayoutMediator(tabLayout, viewPager2) { tab, position ->
           // Set the label name
           tab.text = "OBJECT ${(position + 1)}"
      }.attach()
Copy the code

In this way, the linkage of TAB navigation and page sliding is realized.

3.3.3 Application Scenarios

It can be used for switching between pages of various categories, such as news or e-commerce.

3.4 + BottomNavigationView

3.4.1 Effect display

3.4.2 Code implementation

Listening BottomNavigationView setOnNavigationItemSelectedListener, change ViewPager2 item.

Listen to onPageSelected in ViewPager2 and change the BottomNavigationView item.

Note that the number and location of the two components correspond.

 				// Page adapter
        val fragmentPagerAdapter = FragmentPagerAdapter(this)
        val viewPager2 = findViewById<ViewPager2>(R.id.viewPager2)
        viewPager2.apply {
            adapter = fragmentPagerAdapter
            // Do not preload
            offscreenPageLimit = fragmentPagerAdapter.itemCount
            // Single animation effect
            setPageTransformer(ScaleInTransformer())
        }

        // Bottom menu
        val bottomNavigation = findViewById<BottomNavigationView>(R.id.bottomNavigation)
        // Set the listener
        bottomNavigation.setOnNavigationItemSelectedListener { menuItem ->
            when (menuItem.itemId) {
              // Set the viewPager2 item position
                R.id.menu_messages -> {
                    viewPager2.setCurrentItem(0.true)
                 		// If false is returned, bottomNavigation will not set the clicked item to the selected state
                    true
                }
                R.id.menu_contacts -> {
                    viewPager2.setCurrentItem(1.true)
                    true
                }
                R.id.menu_setting -> {
                    viewPager2.setCurrentItem(2.true)
                    true
                }
                R.id.menu_mine -> {
                    viewPager2.setCurrentItem(3.true)
                    true
                }
                else -> throw IllegalArgumentException("Unset Menu position, please check parameters")}}// Listen for page changes
        viewPager2.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
            override fun onPageSelected(position: Int) {
              	// Set the bottomNavigation Item state
                bottomNavigation.menu.getItem(position).isChecked = true}})Copy the code

3.4.3 Application Scenarios

Multi-page navigation APP with bottom navigation.

3.5 other

3.5.1 track of preloading

OffscreenPageLimit property of ViewPager2.

Set to viewPager2.offscreen_page_limit_default without preloading or caching.

3.5.2 Transition Effect

Single effect and multiple effect Settings are supported, all through the setPageTransformer function.

  1. Effect of single

    Direct incoming ViewPager2. PageTransformer subclass, that is, you can set the corresponding effect.

    MarginPageTransformer page margins are available in the ViewPager2 package and can be used directly in projects.

    You can also customize PageTransformer implementations.

  2. Combined effect

    The CompositePageTransformer class in the ViewPager2 package, which maintains the List.

    Multiple PageTransformer combination effects can be set.

The following provides several effects of display and code, you can learn to customize the implementation of their own effects:

1. Depth change effect

import android.view.View
import androidx.viewpager2.widget.ViewPager2

private const val MIN_SCALE = 0.75 f

class DepthPageTransformer : ViewPager2.PageTransformer {

    override fun transformPage(view: View, position: Float) {
        view.apply {
            val pageWidth = width
            when {
                position < -1- > {// [-Infinity,-1)
                    // This page is way off-screen to the left.
                    alpha = 0f
                }
                position <= 0- > {/ / [- 1, 0]
                    // Use the default slide transition when moving to the left page
                    alpha = 1f
                    translationX = 0f
                    translationZ = 0f
                    scaleX = 1f
                    scaleY = 1f
                }
                position <= 1- > {/ / (0, 1]
                    // Fade the page out.
                    alpha = 1 - position

                    // Counteract the default slide transition
                    translationX = pageWidth * -position
                    // Move it behind the left page
                    translationZ = -1f

                    // Scale the page down (between MIN_SCALE and 1)
                    val scaleFactor = (MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position)))
                    scaleX = scaleFactor
                    scaleY = scaleFactor
                }
                else- > {// (1,+Infinity]
                    // This page is way off-screen to the right.
                    alpha = 0f
                }
            }
        }
    }
}
Copy the code
2. Zoom into effect

import android.view.View
import androidx.viewpager2.widget.ViewPager2
import java.lang.Math.abs

class ScaleInTransformer : ViewPager2.PageTransformer {
  private val mMinScale = DEFAULT_MIN_SCALE
  override fun transformPage(view: View, position: Float) {
    view.elevation = -abs(position)
    val pageWidth = view.width
    val pageHeight = view.height

    view.pivotY = (pageHeight / 2).toFloat()
    view.pivotX = (pageWidth / 2).toFloat()
    if (position < -1) {
      view.scaleX = mMinScale
      view.scaleY = mMinScale
      view.pivotX = pageWidth.toFloat()
    } else if (position <= 1) {
      if (position < 0) {
        val scaleFactor = (1 + position) * (1- mMinScale) + mMinScale view.scaleX = scaleFactor view.scaleY = scaleFactor view.pivotX = pageWidth * (DEFAULT_CENTER +  DEFAULT_CENTER * -position) }else {
        val scaleFactor = (1 - position) * (1 - mMinScale) + mMinScale
        view.scaleX = scaleFactor
        view.scaleY = scaleFactor
        view.pivotX = pageWidth * ((1 - position) * DEFAULT_CENTER)
      }
    } else {
      view.pivotX = 0f
      view.scaleX = mMinScale
      view.scaleY = mMinScale
    }
  }

  companion object {
    const val DEFAULT_MIN_SCALE = 0.85 f
    const val DEFAULT_CENTER = 0.5 f}}Copy the code
3. Zoom into exit effect

private const val MIN_SCALE = 0.85 f
private const val MIN_ALPHA = 0.5 f

class ZoomOutPageTransformer : ViewPager2.PageTransformer {
    override fun transformPage(view: View, position: Float) {
        view.apply {
            val pageWidth = width
            val pageHeight = height
            when {
                position < -1- > {// [-Infinity,-1)
                    // This page is way off-screen to the left.
                    alpha = 0f
                }
                position <= 1- > {/ / [1, 1]
                    // Modify the default slide transition to shrink the page as well
                    val scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position))
                    val vertMargin = pageHeight * (1 - scaleFactor) / 2
                    val horzMargin = pageWidth * (1 - scaleFactor) / 2
                    translationX = if (position < 0) {
                        horzMargin - vertMargin / 2
                    } else {
                        horzMargin + vertMargin / 2
                    }

                    // Scale the page down (between MIN_SCALE and 1)
                    scaleX = scaleFactor
                    scaleY = scaleFactor

                    // Fade the page relative to its size.
                    alpha = (MIN_ALPHA +
                            (((scaleFactor - MIN_SCALE) / (1 - MIN_SCALE)) * (1 - MIN_ALPHA)))
                }
                else- > {// (1,+Infinity]
                    // This page is way off-screen to the right.
                    alpha = 0f
                }
            }
        }
    }
}
Copy the code
4. Page margin effect in PageTransformer

3.5.3 Manual sliding is prohibited

viewPager2.isUserInputEnabled = true or false
Copy the code

3.5.4 Simulated sliding

 	viewPager2.beginFakeDrag()
	if (viewPager2.fakeDragBy(-300f)) {
  	viewPager2.endFakeDrag()
	}
Copy the code

3.5.5 Sliding direction

viewPager2.orientation = ViewPager2.ORIENTATION_VERTICAL or ViewPager2.ORIENTATION_HORIZONTAL
Copy the code

Fourth, extend and expand

  1. How to customize PageTransformer
  2. The Fragment lifecycle changes in ViewPager2
  3. More usage scenarios are extended

5. Reference materials

Still using ViewPager? Time to replace it with ViewPager2!

Official Google Docs

Create a sliding view with tabs using ViewPager2

Thank you!

Pay attention to AutismBug, don’t write bugs!