董事长今天给我下达了一个非常经典的 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 避坑指南:

  1. app:titleEnabled="false":这句非常关键!默认情况下,CollapsingToolbarLayout 会自己接管标题的放大缩小动画。但我们的需求是“展开时标题是‘我的’,折叠时变成‘账号名’”,所以我们要关掉它的默认动画,自己用代码控制!
  2. app:layout_collapseMode
    • parallax(视差):给背景图和头像区用,滑动时会有速度差,显得极其立体高级!
    • pin(固定):给 Toolbar 用,保证滑到最顶上时,它会钉在那里不消失。
  3. 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 = "我的"
            }
        }
    }
}

✨ 最终效果:

  1. 一开始:页面顶部一个大大的沉浸式背景,最上面写着“我的”,下面挂着头像和名字。
  2. 手指上滑:背景图带点视差效果慢慢缩上去,头像跟着往上飘。
  3. 彻底折叠:顶部的 Toolbar 变成了深色(被 contentScrim 染色),同时文字从“我的”瞬间切换成了“Cicida_2026”!

这就是 Android Material Design 带来的布局魔法,没有复杂的动画计算,全靠几个标签和监听器就搞定了!赶紧写进你的代码里试试看吧!🏕️🚀