You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何以编程方式滚动NestedScrollView?实现类WhatsApp折叠头像效果

实现WhatsApp风格的CollapsingToolbar折叠效果(初始显示40%图片,下滑展开)

刚好做过类似的需求,这就给你拆解实现步骤,完全贴合你要的效果:

第一步:调整XML布局结构

首先得把CoordinatorLayout、AppBarLayout、CollapsingToolbarLayout和NestedScrollView的关系理清楚,下面是完整的布局代码,你可以直接参考修改:

<?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_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fitsSystemWindows="true">

        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="300dp" <!-- 这里设置你要的图片总高度 -->
            android:fitsSystemWindows="true"
            app:contentScrim="@color/white"
            <!-- 关键滚动参数:scroll允许滚动,exitUntilCollapsed折叠到Toolbar高度,snap吸附效果 -->
            app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">

            <ImageView
                android:id="@+id/profile_image"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                android:src="@drawable/your_profile_pic"
                app:layout_collapseMode="parallax" <!-- 视差滚动,贴近WhatsApp体验 -->
                app:layout_collapseParallaxMultiplier="0.7" /> <!-- 视差幅度,0-1之间调整 -->

            <!-- 固定在顶部的Toolbar,折叠时会保留 -->
            <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin" />

        </com.google.android.material.appbar.CollapsingToolbarLayout>

    </com.google.android.material.appbar.AppBarLayout>

    <androidx.core.widget.NestedScrollView
        android:id="@+id/nested_scroll_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        <!-- 绑定AppBarLayout的滚动行为 -->
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <!-- 滚动内容区域,确保内容足够长能触发滚动 -->
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:padding="16dp">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="个人资料"
                android:textSize="20sp"
                android:textStyle="bold" />

            <!-- 这里放足够多的内容,比如长文本或者多个控件,保证NestedScrollView可以滚动 -->
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/long_dummy_text"
                android:layout_marginTop="16dp" />

        </LinearLayout>

    </androidx.core.widget.NestedScrollView>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

第二步:代码实现初始折叠状态

要让ImageView初始只显示40%,核心思路是让NestedScrollView在页面加载完成后,自动滚动到指定位置,从而把AppBarLayout折叠到对应状态。下面是Kotlin和Java的实现代码:

Kotlin版本

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_profile)

    val appBarLayout = findViewById<AppBarLayout>(R.id.app_bar_layout)
    val nestedScrollView = findViewById<NestedScrollView>(R.id.nested_scroll_view)
    val collapsingToolbar = findViewById<CollapsingToolbarLayout>(R.id.collapsing_toolbar)

    // 必须等视图测量完成后再计算滚动位置,不然获取到的高度是0
    appBarLayout.post {
        // 获取CollapsingToolbar的总高度
        val totalHeight = collapsingToolbar.height
        // 计算初始要显示的40%高度
        val visibleHeight = (totalHeight * 0.4).toInt()
        // 需要滚动的距离 = 总高度 - 可见高度
        val scrollDistance = totalHeight - visibleHeight

        // 滚动NestedScrollView,实现初始折叠效果
        nestedScrollView.scrollTo(0, scrollDistance)
    }

    // 可选:监听AppBar折叠状态,做额外UI调整(比如显示/隐藏标题)
    appBarLayout.addOnOffsetChangedListener { _, verticalOffset ->
        // verticalOffset为0时完全展开,为负的总高度时完全折叠
        val collapsePercentage = Math.abs(verticalOffset).toFloat() / totalHeight
        // 这里可以根据百分比调整Toolbar标题显示、透明度等
    }
}

Java版本

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_profile);

    AppBarLayout appBarLayout = findViewById(R.id.app_bar_layout);
    NestedScrollView nestedScrollView = findViewById(R.id.nested_scroll_view);
    CollapsingToolbarLayout collapsingToolbar = findViewById(R.id.collapsing_toolbar);

    appBarLayout.post(() -> {
        int totalHeight = collapsingToolbar.getHeight();
        int visibleHeight = (int) (totalHeight * 0.4);
        int scrollDistance = totalHeight - visibleHeight;

        nestedScrollView.scrollTo(0, scrollDistance);
    });

    // 可选的折叠状态监听
    appBarLayout.addOnOffsetChangedListener((appBar, verticalOffset) -> {
        float collapsePercentage = Math.abs(verticalOffset) / (float) collapsingToolbar.getHeight();
        // 自定义UI逻辑,比如调整标题透明度
    });
}

关键注意事项

  1. 视图测量时机:必须用post方法等待视图绘制完成,不然刚启动时获取不到正确的高度,计算出来的滚动距离会出错。
  2. 滚动内容长度:NestedScrollView里的内容必须足够长,能触发滚动,不然折叠/展开效果不会生效。
  3. support库兼容:如果你还在使用旧的support库,把布局里的androidx组件换成android.support.design.widget对应的组件即可。
  4. 视差效果调整:可以修改layout_collapseParallaxMultiplier的值(0-1之间),调整图片滚动的视差幅度,0表示图片不移动,1表示和滚动同步。

内容的提问来源于stack exchange,提问作者Satyasarathi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:32:19