一、缘起:

ViewPager2推出已经有一段时间了,而且官方推出了稳定版本Version 1.0.0,相比ViewPager增加了很多优势,是时候用起来了。

二、优势

1、垂直方向支持
  • ViewPager2 支持垂直分页
<androidx.viewpager2.widget.ViewPager2
            android:id="@+id/viewpager_two"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"/>
  • 代码动态设置方式
// 水平方向
viewpager_two.orientation=ViewPager2.ORIENTATION_HORIZONTAL
// 垂直方向
viewpager_two.orientation=ViewPager2.ORIENTATION_VERTICAL

ps:之前使用VerticalViewpager现在可以改为ViewPager2了

2、从右到左支持
  • 默认为从左到右滑动方向,可以通过设置layoutDirection="rtl"设置为从右到左滑动
<androidx.viewpager2.widget.ViewPager2
            android:id="@+id/viewpager_two"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
             android:layoutDirection="rtl"/>
3、可修改的 Fragment 集合

ViewPager2 支持对可修改的 Fragment 集合进行分页浏览,在底层集合发生更改时调用 notifyDatasetChanged() 来更新界面。

4、DiffUtil

ViewPager2 在 RecyclerView 的基础上构建而成,这意味着它可以访问 DiffUtil 实用程序类。这一点带来了多项优势,但最突出的一项是,这意味着 ViewPager2 对象本身会利用 RecyclerView 类中的数据集更改动画。

三、使用实例

1、添加依赖
  • build.gradle中
dependencies {
    implementation "androidx.viewpager2:viewpager2:1.0.0"
}
2、水平滑动 不指定方向为水平滑动
  • 水平滑动从左到右方向
  • xml文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    <androidx.viewpager2.widget.ViewPager2
            android:id="@+id/viewpager_two"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1" />
</LinearLayout>
  • adapter
class ViewpagerTwoAdapter : RecyclerView.Adapter<ViewpagerTwoAdapter.MyHolder>() {

    private val imgArray = intArrayOf(R.drawable.dog_01, R.drawable.dog_02, R.drawable.dog_03)
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyHolder {
        return MyHolder(
            LayoutInflater.from(parent.context).inflate(R.layout.item_view_pager2, parent, false)
        )
    }

    override fun getItemCount(): Int {
        return 10
    }

    override fun onBindViewHolder(holder: MyHolder, position: Int) {
        holder.ivItem.setImageResource(imgArray[position % imgArray.size])
    }


    class MyHolder(view: View) : RecyclerView.ViewHolder(view) {
        val ivItem: ImageView = view.findViewById(R.id.iv_item)
    }
}
  • 效果图
  • android 使用ViewPage2 android viewpager2_xml

  • 水平滑动从右到左方向
  • 添加方向指定 android:layoutDirection=“rtl”
<androidx.viewpager2.widget.ViewPager2
            android:id="@+id/viewpager_two"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:layoutDirection="rtl"
            />
  • 效果图
3、垂直方向滑动
  • 只需指定android:orientation="vertical"即可
<androidx.viewpager2.widget.ViewPager2
            android:id="@+id/viewpager_two"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:orientation="vertical"/>
  • 效果图
4、结合Fragment使用
  • activity代码
// 结合fragment使用
         viewpager_two.adapter = FragmentViewPagerTwoAdapter(this)
  • adapter 继承FragmentStateAdapter
class FragmentViewPagerTwoAdapter(frag:FragmentActivity) :FragmentStateAdapter(frag){

    override fun getItemCount(): Int {
        return 5
    }

    override fun createFragment(position: Int): Fragment {
        return NormalFragment()
    }
}
  • Fragment代码
class NormalFragment :Fragment(){
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_normal, container, false)
    }
}
  • fragment_normal xml文件
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <ImageView
                android:id="@+id/iv_fragment_normal"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:src="@drawable/dog_01"/>
</androidx.constraintlayout.widget.ConstraintLayout>
  • 效果图

Fragment也可以设置为垂直滑动和从右到左水平滑动,只需根据需要设置orientation和layoutDirection即可

5、结合TabLayout使用
  • 添加依赖
implementation "com.google.android.material:material:1.1.0-beta01"
  • xml文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    <com.google.android.material.tabs.TabLayout
            android:id="@+id/tab_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

    <androidx.viewpager2.widget.ViewPager2
            android:id="@+id/viewpager_two"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1" />
</LinearLayout>
  • activity调用代码
// 结合tableLayout使用
        TabLayoutMediator(tab_layout, viewpager_two) { tab, position ->
            tab.text = "Tab ${(position + 1)}"
        }.attach()

一定要调用attach()方法才起作用

  • 效果图
6、实现ViewPager2.PageTransformer自定义切换效果,设置切换效果
放大进入效果
  • activity代码
viewpager_two.setPageTransformer(ZoomPagerTransformer())
  • ZoomPagerTransformer
private const val MIN_SCALE = 0.85f
private const val MIN_ALPHA = 0.5f
class ZoomPagerTransformer :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 = MIN_SCALE.coerceAtLeast(1 - 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
                }
            }
        }
    }

}
  • 效果图

android 使用ViewPage2 android viewpager2_android 使用ViewPage2_02

层次进入效果
  • activity代码
viewpager_two.setPageTransformer(DepthPageTransformer())
  • DepthPageTransformer
private const val MIN_SCALE = 0.75f

class DepthPageTransformer : ViewPager2.PageTransformer {

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    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
                }
            }
        }
    }
}
  • 效果图
使用CompositePageTransformer实现多个transformer合并使用
  • activity代码
// 多个transformer结合使用
        val compositePageTransformer = CompositePageTransformer()
        compositePageTransformer.addTransformer(DepthPageTransformer())
        // marginTransformer
        compositePageTransformer.addTransformer(MarginPageTransformer(10))
        viewpager_two.setPageTransformer(compositePageTransformer)
  • 效果图