董事长今天给我下达了一个非常经典的 UI 需求!相信很多 Android 开发者在做“我的(个人中心)”页面时都会遇到这个场景:
“要实现一个顶部的可折叠标题栏。展开时,有一个沉浸式图片背景,顶部是页面标题‘我的’,下面是头像,旁边是登录账号。上滑时,背景折叠,折叠后的 Toolbar 显示登录账号。”
这个交互效果非常丝滑而且高级!今天小C就来手把手带你用 CoordinatorLayout + AppBarLayout 把它完美实现!✨
1. 布局结构拆解:洋葱模型
要做这个效果,我们需要把布局像包洋葱一样一层一层套起来:
最外层:CoordinatorLayout (大管家,负责协调所有滑动)
↳ 头部:AppBarLayout (处理顶部滑动逻辑)
↳ 折叠区:CollapsingToolbarLayout (真正会变大变小的魔法容器)
↳ 1. 背景大图 (ImageView)
↳ 2. 个人信息区 (LinearLayout 包含头像和名字)
↳ 3. 顶部工具栏 (Toolbar)
核心 XML 代码实现:
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
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">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="250dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<!-- 魔法容器:exitUntilCollapsed 保证向上滑时保留 Toolbar 的高度 -->
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:contentScrim="?attr/colorPrimary"
app:titleEnabled="false"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<!-- 1. 沉浸式背景图:parallax 产生视差滑动效果 -->
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/bg_header"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.7" />
<!-- 2. 头像和账号信息区:同样设置视差模式,跟着一起滑走 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_marginBottom="40dp"
android:layout_marginStart="20dp"
android:orientation="horizontal"
android:gravity="center_vertical"
app:layout_collapseMode="parallax">
<!-- 头像 -->
<ImageView
android:id="@+id/iv_avatar"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="@drawable/ic_avatar_default"/>
<!-- 账号名字 -->
<TextView
android:id="@+id/tv_account_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="Cicida_2026"
android:textColor="#FFFFFF"
android:textSize="18sp"
android:textStyle="bold"/>
</LinearLayout>
<!-- 3. 顶部 Toolbar:pin 模式保证它始终钉在顶部 -->
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:title="我的"
app:layout_collapseMode="pin" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<!-- 这里放你的 RecyclerView 或者 NestedScrollView -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
💡 XML 避坑指南:
app:titleEnabled="false":这句非常关键!默认情况下,CollapsingToolbarLayout会自己接管标题的放大缩小动画。但我们的需求是“展开时标题是‘我的’,折叠时变成‘账号名’”,所以我们要关掉它的默认动画,自己用代码控制!app:layout_collapseMode:parallax(视差):给背景图和头像区用,滑动时会有速度差,显得极其立体高级!pin(固定):给 Toolbar 用,保证滑到最顶上时,它会钉在那里不消失。
app:layout_behavior:底部的列表一定要加这句,这是告诉底部的列表:“你要乖乖排在 AppBar 的下面,不要被它盖住哦”。
2. Kotlin 代码魔法:动态切换标题
布局写好了,怎么实现“上滑折叠后,Toolbar 的文字从‘我的’变成‘登录账号’”呢?
这就需要监听 AppBar 的滑动折叠偏移量(Offset)啦!
class MyPageFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val appBarLayout = view.findViewById<AppBarLayout>(R.id.app_bar)
val toolbar = view.findViewById<Toolbar>(R.id.toolbar)
val tvAccountName = view.findViewById<TextView>(R.id.tv_account_name)
// 假设这是我们获取到的用户昵称
val userName = "Cicida_2026"
tvAccountName.text = userName
// 监听 AppBar 的滑动折叠高度
appBarLayout.addOnOffsetChangedListener { appBar, verticalOffset ->
// verticalOffset 是个负数,代表向上滑动的像素距离
// appBar.totalScrollRange 是 AppBar 最大可以滑动的总距离
if (kotlin.math.abs(verticalOffset) >= appBar.totalScrollRange) {
// 当滑动的距离 >= 最大折叠距离时,说明【完全折叠】了!
// 把 Toolbar 的标题换成用户的账号名
toolbar.title = userName
} else {
// 只要还没完全折叠(处于展开或滑动中)
// Toolbar 的标题就保持默认的 "我的"
toolbar.title = "我的"
}
}
}
}
✨ 最终效果:
- 一开始:页面顶部一个大大的沉浸式背景,最上面写着“我的”,下面挂着头像和名字。
- 手指上滑:背景图带点视差效果慢慢缩上去,头像跟着往上飘。
- 彻底折叠:顶部的 Toolbar 变成了深色(被
contentScrim染色),同时文字从“我的”瞬间切换成了“Cicida_2026”!
这就是 Android Material Design 带来的布局魔法,没有复杂的动画计算,全靠几个标签和监听器就搞定了!赶紧写进你的代码里试试看吧!🏕️🚀