**1. 概述 **
TabLayout 和 ViewPager2 是实现分页式界面(即通过滑动或点击标签在不同页面间切换)的组合。它们提供了流畅、直观的用户体验,广泛应用于新闻应用、设置界面、商品分类等场景。
ViewPager2: 是ViewPager的现代化替代品,基于RecyclerView构建,支持垂直/水平滑动、RTL 布局、以及更强大的数据集变更动画。它负责管理多个页面(Fragment 或 View)并处理滑动逻辑。TabLayout: 提供了一排水平的标签(Tabs),每个标签对应ViewPager2中的一个页面。它允许用户通过点击标签来切换页面,并能与ViewPager2同步状态(如高亮当前选中的标签)。
将两者结合使用,可以轻松创建出带有顶部导航标签的、可左右滑动的多页面界面。
2. 核心组件与依赖
2.1 添加依赖
ViewPager2 和 TabLayout 都是 Material Components 库的一部分。首先需要在 app/build.gradle 文件中添加依赖:
gradle
dependencies {
// ...
implementation 'androidx.viewpager2:viewpager2:1.0.0'
implementation 'com.google.android.material:material:1.9.0'
}
2.2 布局文件结构
典型的布局文件会将 TabLayout 和 ViewPager2 放在一个垂直的 LinearLayout 或 ConstraintLayout 中。
xml
<!-- res/layout/activity_main.xml -->
<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">
<!-- TabLayout 用于显示标签 -->
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<!-- ViewPager2 用于承载和滑动页面 -->
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
3. 基本使用步骤
实现一个完整的 TabLayout + ViewPager2 功能通常需要以下步骤:
3.1 创建 Fragment 页面
首先,为每个标签页创建一个 Fragment。假设我们有三个页面:首页、发现、我的。
java
// Java - HomeFragment.java
public class HomeFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_home, container, false);
}
}
// DiscoveryFragment.java 和 ProfileFragment.java 结构类似
3.2 创建 ViewPager2 的 Adapter
ViewPager2 需要一个 FragmentStateAdapter(或 RecyclerView.Adapter)来提供页面。对于 Fragment 页面,推荐使用 FragmentStateAdapter。
java
// Java - ViewPagerAdapter.java
public class ViewPagerAdapter extends FragmentStateAdapter {
private final List<Fragment> fragmentList;
private final List<String> titleList;
public ViewPagerAdapter(@NonNull FragmentActivity fa, List<Fragment> fragments, List<String> titles) {
super(fa);
this.fragmentList = fragments;
this.titleList = titles;
}
@NonNull
@Override
public Fragment createFragment(int position) {
return fragmentList.get(position);
}
@Override
public int getItemCount() {
return fragmentList.size();
}
// 可选:提供一个方法来获取标题,用于 TabLayout
public String getTitle(int position) {
return titleList.get(position);
}
}
3.3 在 Activity 中组装并关联
在 Activity 的 onCreate 方法中,初始化 ViewPager2 和 TabLayout,并将它们关联起来。
java
// Java - MainActivity.java
public class MainActivity extends AppCompatActivity {
private ViewPager2 mViewPager;
private TabLayout mTabLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mViewPager = findViewById(R.id.view_pager);
mTabLayout = findViewById(R.id.tab_layout);
// 1. 准备 Fragment 和标题数据
List<Fragment> fragments = new ArrayList<>();
fragments.add(new HomeFragment());
fragments.add(new DiscoveryFragment());
fragments.add(new ProfileFragment());
List<String> titles = Arrays.asList("首页", "发现", "我的");
// 2. 设置 ViewPager2 的 Adapter
ViewPagerAdapter adapter = new ViewPagerAdapter(this, fragments, titles);
mViewPager.setAdapter(adapter);
// 3. 将 TabLayout 与 ViewPager2 关联
new TabLayoutMediator(mTabLayout, mViewPager,
(tab, position) -> tab.setText(titles.get(position))
).attach();
}
}
关键点解释:
TabLayoutMediator: 这是连接TabLayout和ViewPager2的桥梁。它的构造函数接受一个(TabLayout.Tab, int) -> Unit的 lambda 表达式(在 Java 中是一个TabConfigurationStrategy接口),用于为每个位置的标签设置文本、图标等属性。
4. TabLayout 的常用配置
TabLayout 提供了多种方式来自定义其外观和行为。
4.1 XML 属性配置
xml
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
<!-- 设置标签模式 -->
app:tabMode="fixed" <!-- fixed (默认): 所有标签均分宽度; scrollable: 标签可滚动 -->
<!-- 设置标签重力 -->
app:tabGravity="fill" <!-- fill (默认, 与 fixed 模式搭配): 填充整个 TabLayout; center: 居中 -->
<!-- 自定义文本样式 -->
app:tabTextAppearance="@style/MyTabTextAppearance"
<!-- 设置指示器颜色和高度 -->
app:tabIndicatorColor="@color/colorAccent"
app:tabIndicatorHeight="4dp"
<!-- 设置未选中/选中文本颜色 -->
app:tabTextColor="@color/unselected_color"
app:tabSelectedTextColor="@color/selected_color" />
4.2 程序化配置
也可以在 Java 代码中动态修改 TabLayout 的属性。
java
// Java
mTabLayout.setTabMode(TabLayout.MODE_SCROLLABLE); // 设置为可滚动模式
mTabLayout.setTabGravity(TabLayout.GRAVITY_CENTER); // 设置标签居中
// 为特定标签设置图标
mTabLayout.getTabAt(0).setIcon(R.drawable.ic_home);
5. 最佳实践与注意事项
-
优先使用
ViewPager2:ViewPager2是ViewPager的官方继任者,修复了许多旧版问题,并提供了更好的性能和功能(如垂直方向)。应始终在新项目中使用ViewPager2。 -
TabLayoutMediator是关键 : 不要再使用已废弃的setupWithViewPager()方法。TabLayoutMediator是官方推荐的、类型安全的连接方式。 -
选择合适的
tabMode- 如果标签数量少(≤4)且宽度固定,使用
app:tabMode="fixed"。 - 如果标签数量多或长度不一,使用
app:tabMode="scrollable"。
- 如果标签数量少(≤4)且宽度固定,使用
-
预加载页面 :
ViewPager2默认会预加载相邻的页面(setOffscreenPageLimit(1))。如果页面初始化开销大,可以适当调整此值,但不要设为 0。 -
处理生命周期 :
FragmentStateAdapter会自动管理 Fragment 的生命周期,确保在滑动时正确地创建和销毁 Fragment,避免内存泄漏。 -
性能优化 : 如果页面内容复杂,考虑在 Fragment 的
setUserVisibleHint(已废弃) 或FragmentTransaction.setMaxLifecycle(推荐) 中实现懒加载,只在页面对用户可见时才加载数据。 -
无障碍性: 确保为每个 Tab 提供清晰的文本描述,以支持屏幕阅读器。
6. 结论
TabLayout 和 ViewPager2 的组合是构建现代 Android 应用分页界面的标准方案。通过 TabLayoutMediator 的简单连接,开发者可以快速实现一个功能完整、交互流畅的多标签页面。