CoordinatorLayout、AppBarLayout 和 TabLayout 是 Android Material Design 中实现高级交互和动效的核心组件。它们组合使用可以实现如工具栏折叠、滑动联动、标签页联动等优雅的 UI 效果。
一、核心组件原理解析
1. CoordinatorLayout
- 作用:是一个增强型的
FrameLayout,作为父容器,负责协调其子 View 之间的交互与动画。 - 核心机制:
- 使用
Behavior类来定义子 View 之间的交互行为(如滑动、点击等)。 - 子 View 可以通过
app:layout_behavior属性指定其行为。 - 它本身不处理滚动,而是监听嵌套滚动事件(NestedScrolling),并将事件分发给具有
Behavior的子 View。
- 使用
2. AppBarLayout
- 作用:是
LinearLayout(垂直方向)的子类,用于包裹工具栏类组件(如Toolbar、TabLayout),并支持滚动响应。 - 关键特性:
- 必须是
CoordinatorLayout的直接子 View。 - 支持
scrollFlags属性,控制其在滚动时的行为。 - 内部使用
NestedScrollView或RecyclerView触发滚动事件。
- 必须是
3. TabLayout
- 作用:提供标签页切换功能,常用于顶部导航。
- 与 AppBarLayout 集成:
- 放在
AppBarLayout内部,随滚动一起折叠/展开。 - 可与
ViewPager2或ViewPager联动,实现页面滑动同步。
- 放在
4. 核心属性:app:layout_scrollFlags
这是实现动效的关键,设置在 AppBarLayout 的子 View 上(如 Toolbar、TabLayout):
| Flag | 说明 |
|---|---|
scroll | 该 View 会随着内容滚动而一起滚动(必须有此 flag 才能触发折叠) |
enterAlways | 向下滚动时,立即显示该 View(即使内容未完全滚动) |
exitUntilCollapsed | 滚动出屏幕,但保留最小高度(常用于折叠工具栏) |
enterAlwaysCollapsed | 配合 enterAlways,下拉时先以最小高度显示,再展开 |
snap | 滚动停止时,自动“吸附”到展开或折叠状态 |
注意:必须至少设置
scroll,否则不会响应滚动。
二、联动原理详解
1. 协同工作流程
-
滚动事件传递:
- 用户滑动 RecyclerView/ViewPager。
- CoordinatorLayout 通过 onNestedScroll 将事件传递给 AppBarLayout。
- AppBarLayout 根据 layout_scrollFlags 决定是否折叠/展开子视图(如 Toolbar、TabLayout)。
-
标签与页面同步:
- TabLayout 通过 ViewPager 的 OnPageChangeListener 更新选中标签。
- 用户点击标签时,TabLayout 调用 ViewPager.setCurrentItem() 切换页面。
2. 联动解析
下面是一个最常见的布局结构:
<androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.appbar.AppBarLayout>
<com.google.android.material.appbar.MaterialToolbar
app:layout_scrollFlags="scroll|enterAlways|snap"/>
<com.google.android.material.tabs.TabLayout
app:layout_scrollFlags="scroll|enterAlways|snap"/>
</com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager2.widget.ViewPager2
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
联动流程(用户向上滚动 ViewPager2 内的列表时)
-
手势开始: 用户手指在 ViewPager2(内部是 RecyclerView)上向上滑动。
-
事件分发: RecyclerView(作为 NestedScrollingChild)将滚动事件传递给它的父布局 CoordinatorLayout(作为 NestedScrollingParent)。
-
Behavior 拦截: CoordinatorLayout 询问它的子 View:“谁想处理这个滚动事件?”。此时,AppBarLayout 的 Behavior(AppBarLayout.Behavior)会响应说:“我来处理!”
-
消费滚动距离: AppBarLayout.Behavior 根据子 View 的 scrollFlags,将手指滑动的距离(dy)转化为 AppBarLayout 的垂直偏移量。具体来说,它会让 AppBarLayout 向上平移(translationY)相应的距离。
-
子 View 联动: 由于 AppBarLayout 整体向上移动,其内部的 Toolbar 和 TabLayout(因为它们设置了 scroll 标志)也会随之向上滑出屏幕。
-
内容区域补偿: 为了让 ViewPager2 的内容能完整填充 AppBarLayout 滑走后的空间,ViewPager2 设置了 appbar_scrolling_view_behavior。这个 Behavior 会动态调整 ViewPager2 的顶部内边距(paddingTop),使其始终等于 AppBarLayout 的当前可见高度。这样就实现了内容区域的“无缝衔接”。
-
反向滚动(用户向下滚动)时,过程相反,AppBarLayout 会滑回原位。
三、常用动效实现
1.折叠式工具栏(Collapsing Toolbar)
<CoordinatorLayout>
<AppBarLayout>
<CollapsingToolbarLayout
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<ImageView /> <!-- 背景图 -->
<Toolbar app:layout_collapseMode="pin" />
</CollapsingToolbarLayout>
<TabLayout
app:layout_scrollFlags="scroll"
app:layout_collapseMode="pin" />
</AppBarLayout>
<RecyclerView
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</CoordinatorLayout>
layout_collapseMode="pin":固定该 View 在折叠区域顶部。layout_collapseMode="parallax":背景图视差滚动。
2. TabLayout 随 AppBar 折叠隐藏
<AppBarLayout>
<Toolbar app:layout_scrollFlags="scroll|enterAlways" />
<TabLayout
app:layout_scrollFlags="scroll"
app:tabMode="scrollable" />
</AppBarLayout>
- 下滑时,
Toolbar和TabLayout一起隐藏。 - 上滑时,
Toolbar立即出现(enterAlways),TabLayout随后出现。
3. TabLayout 固定在顶部,Toolbar 折叠
<AppBarLayout>
<Toolbar
app:layout_scrollFlags="scroll|exitUntilCollapsed" />
<TabLayout
app:layout_scrollFlags="scroll"
app:layout_collapseMode="pin" />
</AppBarLayout>
Toolbar可折叠,TabLayout始终固定在顶部。
4. 与 ViewPager2 联动
val viewPager = findViewById<ViewPager2>(R.id.viewPager)
val tabLayout = findViewById<TabLayout>(R.id.tabLayout)
TabLayoutMediator(tabLayout, viewPager) { tab, position ->
tab.text = "Tab ${position + 1}"
}.attach()
- 实现标签页与页面滑动同步。
- 滚动
RecyclerView时,AppBarLayout折叠,TabLayout联动隐藏或固定。
四、注意事项
1. 层级关系必须正确:
CoordinatorLayout
├── AppBarLayout
│ ├── Toolbar
│ └── TabLayout
└── 内容视图(RecyclerView等) + app:layout_behavior
2. 内容视图必须设置 behavior:
app:layout_behavior="@string/appbar_scrolling_view_behavior"
否则无法触发滚动事件。
3. 避免嵌套滚动冲突:
- 使用
NestedScrollView时注意性能。 RecyclerView推荐使用。
4. Material Design 依赖:
implementation 'com.google.android.material:material:1.11.0'
五、总结
| 组件 | 作用 | 关键点 |
|---|---|---|
CoordinatorLayout | 动画协调中枢 | 父容器,分发滚动事件 |
AppBarLayout | 滚动响应容器 | 必须直接子 View,设置 scrollFlags |
TabLayout | 标签导航 | 可折叠或固定,与 ViewPager 联动 |
通过合理配置 scrollFlags 和 collapseMode,可以实现丰富的视觉动效,提升用户体验。推荐在 Fragment 或 Activity 中结合 ViewPager2 使用,构建现代 Material Design 界面。
六、典型应用场景
- 新闻类应用:顶部为可折叠的图片轮播栏,下方为分类标签页(如“推荐”“科技”“体育”)。
- 电商类应用:商品详情页中,顶部为商品图片和名称,下方为“详情”“评价”“推荐”标签页。
- 社交类应用:用户个人主页中,顶部为头像和简介,下方为“动态”“作品”“收藏”标签页。
2894





