如何以编程方式滚动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逻辑,比如调整标题透明度 }); }
关键注意事项
- 视图测量时机:必须用
post方法等待视图绘制完成,不然刚启动时获取不到正确的高度,计算出来的滚动距离会出错。 - 滚动内容长度:NestedScrollView里的内容必须足够长,能触发滚动,不然折叠/展开效果不会生效。
- support库兼容:如果你还在使用旧的support库,把布局里的
androidx组件换成android.support.design.widget对应的组件即可。 - 视差效果调整:可以修改
layout_collapseParallaxMultiplier的值(0-1之间),调整图片滚动的视差幅度,0表示图片不移动,1表示和滚动同步。
内容的提问来源于stack exchange,提问作者Satyasarathi
相关产品推荐
相关产品推荐

