Android 入门到实战(三):ViewPager及ViewPager2多页面布局

一. 引言

在 Android 应用开发中,实现多页面的左右滑动切换,是非常常见且实用的交互方式。ViewPager 组件正是为此而生,帮助我们轻松管理和切换多个页面内容。

不过,随着 Android Jetpack 的发展,Google 推出了 ViewPager 的升级版本 ------ ViewPager2,它在功能和性能上都有显著提升,成为了新的官方推荐组件。

本篇文章将带你快速了解旧版 ViewPager 的基本情况及它的两种常用适配器(FragmentPagerAdapter 和 FragmentStatePagerAdapter)之间的区别,随后重点介绍 ViewPager2 的使用方法,并演示如何配合 TabLayout 实现漂亮的滑动标签页效果。通过一个简单的 Activity + 3 个 Fragment 示例,帮助你快速掌握多页面滑动切换的核心技巧。

无论你是刚接触 ViewPager 相关组件,还是想了解 ViewPager2 的实战用法,这篇内容都会为你提供清晰且实用的指导。

二. 旧版 ViewPager 简介及适配器区别

2.1 什么是 ViewPager?

ViewPager 是 Android Support Library(现为 AndroidX)中提供的一个经典组件,用于在多个页面之间实现左右滑动切换。它内部管理多个页面视图,支持手势滑动、页面切换动画以及预加载等功能,使得多页面导航体验更加流畅自然。

2.2 FragmentPagerAdapter 和 FragmentStatePagerAdapter 的区别

在使用 ViewPager 管理 Fragment 页面时,通常会用到两种适配器:

FragmentPagerAdapter

  • 适用于页面数量较少且固定的情况。
  • 它会保留所有 Fragment 的实例,页面切换时仅隐藏或显示。
  • 因为会一直持有所有 Fragment,占用更多内存,适合 Tab 页数较少的场景。

FragmentStatePagerAdapter

  • 适用于页面较多或者动态变化的情况。
  • 它会在 Fragment 不可见时销毁其视图和状态,仅保存必要的状态信息。
  • 能有效节省内存,适合需要管理大量页面的情况。

2.3 代码示例(简要)

Kotlin 复制代码
class MyPagerAdapter(fm: FragmentManager) : FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
    override fun getCount() = 3
    override fun getItem(position: Int): Fragment {
        return when(position) {
            0 -> FragmentA()
            1 -> FragmentB()
            else -> FragmentC()
        }
    }
}

如果用 FragmentStatePagerAdapter,写法类似,只是继承不同。

2.4 为什么推荐使用 ViewPager2?

尽管旧版 ViewPager 仍在一些项目中使用,但它存在一些设计和性能上的限制,比如:

  • 只能水平方向滑动(ViewPager2 支持垂直滑动)
  • 不支持 RecyclerView 的所有优势(ViewPager2 基于 RecyclerView 实现)
  • 适配现代架构组件支持较弱

因此,Google 推荐在新项目中使用功能更强、灵活性更高的 ViewPager2。

三. ViewPager2 介绍

3.1 ViewPager2 是什么?

ViewPager2 是 Google 推出的 ViewPager 升级版,基于 RecyclerView 实现,拥有更强的功能和更好的性能,同时完美支持 AndroidX 和 Jetpack 架构组件。它的 API 设计更灵活,兼容性更好,是当前新项目的首选。

3.2 相比旧版的主要改进

特性 ViewPager ViewPager2
滑动方向 仅支持水平方向 支持水平 & 垂直
底层实现 自定义 Layout 基于 RecyclerView
数据更新 需调用 notifyDataSetChanged(),机制复杂 直接使用 RecyclerView Adapter 更新机制
生命周期 与 Fragment 生命周期适配不够好 完全兼容 Fragment Lifecycle & LiveData
反向布局 不支持 支持(RTL,倒序显示等)

3.3 基本使用方式

ViewPager2 继承自 ViewGroup,与 RecyclerView 的 Adapter 配合使用,官方推荐配合 FragmentStateAdapter 来管理 Fragment 页面。它的使用步骤通常为:

  1. 在布局文件中添加 ViewPager2
  2. 创建一个继承自 FragmentStateAdapter 的适配器
  3. 在 Activity/Fragment 中将适配器绑定到 ViewPager2
  4. (可选)与 TabLayout 结合,使用 TabLayoutMediator 进行绑定

四. ViewPager2 + TabLayout 实现滑动 Tab 布局

下面我们用一个简单的 Activity + 3 个 Fragment,演示如何用 ViewPager2 配合 TabLayout 实现滑动标签页效果。

4.1 activity布局文件

XML 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:id="@+id/main">

    <!-- TabLayout -->
    <com.google.android.material.tabs.TabLayout
        android:id="@+id/tabLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:tabIndicatorColor="@android:color/holo_blue_dark"
        app:tabSelectedTextColor="@android:color/holo_blue_dark"
        app:tabTextColor="@android:color/darker_gray" />

    <!-- ViewPager2 -->
    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/viewPager2"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

</LinearLayout>

4.2 Fragment 布局

以fragment_home.xml为例:

XML 复制代码
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:tools="http://schemas.android.com/tools"
    android:gravity="center"
    tools:context=".page.MineFragment">

    <TextView
        android:id="@+id/tvTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="首页"
        android:layout_gravity="center"
        android:textSize="24sp" />

</FrameLayout>

4.3 Fragment 类

事实上这都是工具为我们自动创建的以HomeFragment.kt为例:

Kotlin 复制代码
class HomeFragment : Fragment() {
    // TODO: Rename and change types of parameters
    private var param1: String? = null
    private var param2: String? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        arguments?.let {
            param1 = it.getString(ARG_PARAM1)
            param2 = it.getString(ARG_PARAM2)
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_home, container, false)
    }

    companion object {
        /**
         * Use this factory method to create a new instance of
         * this fragment using the provided parameters.
         *
         * @param param1 Parameter 1.
         * @param param2 Parameter 2.
         * @return A new instance of fragment HomeFragment.
         */
        // TODO: Rename and change types and number of parameters
        @JvmStatic
        fun newInstance(param1: String, param2: String) =
            HomeFragment().apply {
                arguments = Bundle().apply {
                    putString(ARG_PARAM1, param1)
                    putString(ARG_PARAM2, param2)
                }
            }
    }
}

4.4 适配器

MainPagerAdapter.kt

Kotlin 复制代码
package com.example.viewpagerexample.main

import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.example.viewpagerexample.page.DiscoverFragment
import com.example.viewpagerexample.page.HomeFragment
import com.example.viewpagerexample.page.MineFragment

class MainPagerAdapter(activity: FragmentActivity): FragmentStateAdapter(activity) {
    private val fragments = listOf(
        HomeFragment(),
        DiscoverFragment(),
        MineFragment()
    )

    override fun getItemCount() = fragments.size
    override fun createFragment(position: Int) = fragments[position]
}

4.5 Activity 绑定逻辑

MainActivity.kt

Kotlin 复制代码
    /// 配置tab
    private fun setupTabLayout() {
        val viewPager = findViewById<androidx.viewpager2.widget.ViewPager2>(R.id.viewPager2)
        val tabLayout = findViewById<com.google.android.material.tabs.TabLayout>(R.id.tabLayout)

        // 设置ViewPager2的适配器
        viewPager.adapter = MainPagerAdapter(this)

        // 使用 TabLayoutMediator 来绑定
        val titles = listOf("首页", "发现", "我的")
        TabLayoutMediator(tabLayout, viewPager) { tab, position ->
            tab.text = titles[position]
        }.attach()

    }

效果如下:

五. 结语

在 Android 界面开发中,ViewPager2 搭配 TabLayout 是一种高效、直观的多页面切换方案。通过 FragmentStateAdapter,我们可以方便地将多个 Fragment 绑定到滑动视图中,而 TabLayoutMediator 则免去了手动同步标签与页面状态的繁琐逻辑,让交互更加顺畅自然。

相比旧版 ViewPager,ViewPager2 在性能、可扩展性、布局灵活性等方面都有显著提升,支持垂直滑动、RTL 布局、RecyclerView 优化等特性。对于新项目而言,已经没有理由再去使用旧的 ViewPager 与 FragmentPagerAdapter。

至此,我们通过一个 单 Activity + 多 Fragment + TabLayout + ViewPager2 的实战案例,完成了从基本使用到交互优化的全过程。掌握了这一套模式,你就可以轻松实现首页导航、功能分类、内容切换等多种常见 UI 场景,为应用提供更优的用户体验。

相关推荐
阿巴斯甜1 天前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker1 天前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95271 天前
Andorid Google 登录接入文档
android
黄林晴1 天前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab2 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿2 天前
Android MediaPlayer 笔记
android
Jony_2 天前
Android 启动优化方案
android
阿巴斯甜2 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇2 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_2 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android