在 Android 开发中,Tab 切换是常见的 UI 交互场景(如首页分类、我的页面选项卡等)。本文将以 TabLayout + ViewPager2 组合为例,带初学者一步步实现 Tab 点击切换功能,适配 Android Studio 2025
、minSdk 26
,使用 Java 语言开发,流程清晰且易上手。
一、项目背景
配置项 | 具体信息 |
---|---|
开发工具 | Android Studio 2025 |
最小兼容版本 | minSdk = 26(Android 8.0) |
开发语言 | Java |
核心组件 | TabLayout + ViewPager2 |
依赖版本 | androidx.viewpager2:viewpager2:1.1.0 |
二、实现步骤(详细版)
1. 配置 ViewPager2 依赖
首先需要在项目中引入 ViewPager2 的官方依赖,用于承载 Tab 对应的内容页面。
操作步骤:
-
打开项目的
app/build.gradle.kts
(或build.gradle
,根据项目结构选择); -
在
dependencies
闭包中添加 ViewPager2 依赖; -
点击编辑器右上角的 Sync Now 按钮,下载并同步依赖。
kotlin
scss
// app/build.gradle.kts
dependencies {
// ViewPager2 核心依赖(用于内容页面切换)
implementation("androidx.viewpager2:viewpager2:1.1.0")
// Material Design 依赖(包含 TabLayout,若项目已引入可忽略)
implementation("com.google.android.material:material:1.12.0")
}
⚠️ 注意:若项目未引入 Material Design 依赖,TabLayout 会报错,需补充上述
material
依赖。
2. 编写布局文件
需创建两个核心布局:
- Activity 布局:包含 TabLayout(顶部选项卡)和 ViewPager2(内容容器);
- Fragment 布局:每个 Tab 对应的内容页面(如 "平台数据""平台日志" 页面)。
2.1 Activity 主布局(activity_main.xml)
采用垂直 LinearLayout 布局,TabLayout 在上,ViewPager2 在下(占满剩余空间)。
xml
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"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@drawable/main_gradient" <!-- 可选:背景渐变,若无可删 -->
tools:context=".MainActivity">
<!-- 1. TabLayout:顶部选项卡 -->
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent" <!-- 原200dp改为match_parent,适配全屏 -->
android:layout_height="wrap_content"
android:background="@android:color/transparent"
app:tabSelectedTextColor="@color/blue" <!-- 选中Tab的文字颜色 -->
app:tabTextColor="@color/black" <!-- 未选中Tab的文字颜色 -->
app:tabIndicatorColor="@color/blue" <!-- 选中Tab的下划线颜色 -->
app:tabIndicatorHeight="2dp" <!-- 下划线高度 -->
app:tabMode="fixed" <!-- Tab固定排列(适合少量Tab) -->
app:tabPaddingHorizontal="20dp" <!-- Tab左右内边距,避免拥挤 -->
app:tabTextSize="16sp" /> <!-- 文字大小 -->
<!-- 2. ViewPager2:内容容器(占满剩余空间) -->
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" /> <!-- 用weight占满剩余高度 -->
</LinearLayout>
2.2 Fragment 内容布局(2 个)
创建两个 Fragment 布局,分别对应 "平台数据" 和 "平台日志" 页面(结构类似,仅内容区分)。
(1)平台数据 Fragment 布局(fragment_platform_data.xml)
xml
ini
<?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:gravity="center"
android:background="@color/white">
<TextView
android:id="@+id/tv_platform_data"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="平台数据页面"
android:textSize="18sp"
android:textColor="@color/black" />
</LinearLayout>
(2)平台日志 Fragment 布局(fragment_platform_log.xml)
xml
ini
<?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:gravity="center"
android:background="@color/white">
<TextView
android:id="@+id/tv_platform_log"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="平台日志页面"
android:textSize="18sp"
android:textColor="@color/black" />
</LinearLayout>
2.3 补充颜色资源(colors.xml)
在 res/values/colors.xml
中定义用到的颜色(确保与布局中的颜色引用对应):
xml
xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 基础颜色 -->
<color name="black">#000000</color>
<color name="blue">#37A6EB</color> <!-- Tab选中色/下划线色 -->
<color name="white">#FFFFFF</color>
<color name="gray">#545454</color>
<color name="light_gray">#F5F5F5</color>
<!-- 主题颜色(适配Material Design) -->
<color name="colorPrimary">#37A6EB</color>
<color name="colorPrimaryDark">#0277BD</color>
<color name="colorAccent">#FF4081</color>
</resources>
3. 创建 Fragment 逻辑类
Fragment 是 ViewPager2 承载的内容单元,需创建两个 Fragment 类,分别关联上述布局。
3.1 平台数据 Fragment(PlatformDataFragment.java)
java
运行
scala
package com.example.lionlite_user_app;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
public class PlatformDataFragment extends Fragment {
// 实例化方法(可选:用于传递参数,初学者可先保留)
public static PlatformDataFragment newInstance() {
return new PlatformDataFragment();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// 关联Fragment布局
View view = inflater.inflate(R.layout.fragment_platform_data, container, false);
// 若需修改TextView内容,可在此处初始化(示例)
// TextView tvData = view.findViewById(R.id.tv_platform_data);
// tvData.setText("自定义平台数据内容");
return view;
}
}
3.2 平台日志 Fragment(PlatformLogFragment.java)
⚠️ 注意:原内容中此类代码复制错误(类名重复),以下为修正版:
java
运行
scala
package com.example.lionlite_user_app;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
public class PlatformLogFragment extends Fragment {
// 实例化方法
public static PlatformLogFragment newInstance() {
return new PlatformLogFragment();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// 关联Fragment布局(注意是fragment_platform_log)
View view = inflater.inflate(R.layout.fragment_platform_log, container, false);
return view;
}
}
4. 编写 ViewPager2 适配器(TabPagerAdapter.java)
适配器用于将 Fragment 与 ViewPager2 绑定,负责创建 Fragment、返回 Tab 数量和标题。
java
运行
java
package com.example.lionlite_user_app;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import java.util.ArrayList;
import java.util.List;
public class TabPagerAdapter extends FragmentStateAdapter {
// 1. 存储 Tab 标题和对应的 Fragment
private final List<String> tabTitles = new ArrayList<>();
private final List<Fragment> tabFragments = new ArrayList<>();
// 2. 构造方法(接收宿主Activity)
public TabPagerAdapter(@NonNull FragmentActivity fragmentActivity) {
super(fragmentActivity);
// 初始化 Tab 数据(标题 + Fragment 对应)
initTabData();
}
// 3. 初始化 Tab 标题和 Fragment
private void initTabData() {
tabTitles.add("平台数据");
tabFragments.add(PlatformDataFragment.newInstance());
tabTitles.add("平台日志");
tabFragments.add(PlatformLogFragment.newInstance());
}
// 4. 创建对应位置的 Fragment(核心方法)
@NonNull
@Override
public Fragment createFragment(int position) {
return tabFragments.get(position);
}
// 5. 返回 Tab 总数(ViewPager2 页数)
@Override
public int getItemCount() {
return tabFragments.size();
}
// 6. 提供 Tab 标题(给 TabLayout 调用)
public String getTabTitle(int position) {
return tabTitles.get(position);
}
}
5. 关联 TabLayout 与 ViewPager2(MainActivity.java)
在 MainActivity 中完成 TabLayout 和 ViewPager2 的绑定,实现 "点击 Tab 切换页面""滑动页面切换 Tab" 的联动效果。
java
运行
scala
package com.example.lionlite_user_app;
import android.os.Bundle;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.viewpager2.widget.ViewPager2;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 启用EdgeToEdge(沉浸式状态栏,可选)
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
// 处理状态栏内边距(避免内容被状态栏遮挡)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
// 1. 初始化控件
TabLayout tabLayout = findViewById(R.id.tab_layout);
ViewPager2 viewPager = findViewById(R.id.view_pager);
// 2. 给 ViewPager2 设置适配器
TabPagerAdapter adapter = new TabPagerAdapter(this);
viewPager.setAdapter(adapter);
// 3. 关联 TabLayout 和 ViewPager2(核心:实现联动)
new TabLayoutMediator(
tabLayout, // 要关联的 TabLayout
viewPager, // 要关联的 ViewPager2
(tab, position) -> { // 回调:给每个 Tab 设置标题
tab.setText(adapter.getTabTitle(position));
}
).attach(); // ⚠️ 必须调用 attach(),否则绑定失败
}
}
三、常见问题排查(初学者必看)
- TabLayout 找不到类?
→ 检查是否引入 Material Design 依赖(见步骤 1 的material
依赖)。 - Fragment 布局不显示?
→ 确认 Fragment 中inflate
的布局文件名正确(如fragment_platform_log
而非fragment_platform_data
)。 - Tab 点击无反应?
→ 检查是否调用TabLayoutMediator
的attach()
方法(步骤 5 的关键代码)。 - ViewPager2 滑动卡顿?
→ 避免在 Fragment 的onCreateView
中做耗时操作(如网络请求),可延迟初始化。
四、扩展优化(进阶方向)
- 修改 Tab 样式 :如添加图标(
tab.setIcon(R.drawable.ic_data)
)、修改选中背景色; - 添加切换动画 :通过
viewPager.setPageTransformer()
自定义页面切换动画; - 支持更多 Tab :将
app:tabMode="fixed"
改为app:tabMode="scrollable"
,实现可滚动的 Tab; - 保存 Fragment 状态 :在 ViewPager2 中设置
viewPager.setOffscreenPageLimit(2)
(缓存 2 个页面,避免切换时重建)。
五、总结
本文通过 5 个核心步骤 实现了 Tab 切换功能,核心逻辑是:
TabLayout(用户交互)
→ TabLayoutMediator(联动桥梁)
→ ViewPager2(内容容器)
→ TabPagerAdapter(数据适配)
→ Fragment(内容单元)