CoordinatorLayout双Toolbar需求:仅第二个随滚动折叠
嘿,这个需求我熟!要实现只有第二个Toolbar在向下滚动时折叠,核心就是给第二个Toolbar定制一个专属的滚动Behavior,让它跟着滚动事件「动起来」,而第一个Toolbar保持固定不动。下面一步步来教你实现:
实现步骤与代码示例
1. 先搭好布局结构
在CoordinatorLayout里,第一个Toolbar直接固定在顶部,不需要绑定任何滚动相关属性;第二个Toolbar要绑定我们自定义的Behavior,下方放置可滚动的内容(比如RecyclerView或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"> <!-- 第一个固定Toolbar:不参与滚动折叠 --> <com.google.android.material.appbar.MaterialToolbar android:id="@+id/first_toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="@color/primary_500" app:title="固定顶部Toolbar"/> <!-- 第二个可折叠Toolbar:绑定自定义Behavior --> <com.google.android.material.appbar.MaterialToolbar android:id="@+id/second_toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:layout_below="@id/first_toolbar" android:background="@color/secondary_500" app:title="可折叠Toolbar" app:layout_behavior=".ScrollFoldSecondToolbarBehavior"/> <!-- 可滚动内容区:比如RecyclerView --> <androidx.recyclerview.widget.RecyclerView android:id="@+id/content_recycler" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@id/second_toolbar" app:layout_anchor="@id/second_toolbar" app:layout_anchorGravity="bottom"/> </androidx.coordinatorlayout.widget.CoordinatorLayout>
2. 自定义滚动Behavior
这是实现效果的关键!我们写一个继承自CoordinatorLayout.Behavior的类,监听垂直滚动事件,控制第二个Toolbar的偏移量,实现折叠/展开效果。
Kotlin版本代码:
import android.content.Context import android.util.AttributeSet import android.view.View import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.view.ViewCompat class ScrollFoldSecondToolbarBehavior(context: Context, attrs: AttributeSet?) : CoordinatorLayout.Behavior<View>(context, attrs) { private var toolbarHeight = 0 // 记录Toolbar的初始高度 override fun onLayoutChild(parent: CoordinatorLayout, child: View, layoutDirection: Int): Boolean { toolbarHeight = child.height return super.onLayoutChild(parent, child, layoutDirection) } // 只响应垂直方向的滚动事件 override fun onStartNestedScroll( coordinatorLayout: CoordinatorLayout, child: View, directTargetChild: View, target: View, axes: Int, type: Int ): Boolean { return axes == ViewCompat.SCROLL_AXIS_VERTICAL } // 根据滚动距离调整Toolbar的位置:向下滚隐藏,向上滚恢复 override fun onNestedPreScroll( coordinatorLayout: CoordinatorLayout, child: View, target: View, dx: Int, dy: Int, consumed: IntArray, type: Int ) { super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type) // 限制偏移范围:完全隐藏(-toolbarHeight)到完全显示(0) val newY = child.y - dy child.y = newY.coerceIn(-toolbarHeight.toFloat(), 0f) } }
Java版本代码:
import android.content.Context; import android.util.AttributeSet; import android.view.View; import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.core.view.ViewCompat; public class ScrollFoldSecondToolbarBehavior extends CoordinatorLayout.Behavior<View> { private int toolbarHeight = 0; public ScrollFoldSecondToolbarBehavior(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onLayoutChild(CoordinatorLayout parent, View child, int layoutDirection) { toolbarHeight = child.getHeight(); return super.onLayoutChild(parent, child, layoutDirection); } @Override public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int axes, int type) { return axes == ViewCompat.SCROLL_AXIS_VERTICAL; } @Override public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed, int type) { super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type); float newY = child.getY() - dy; // 限制偏移范围,避免Toolbar滚出不合理区域 child.setY(Math.max(-toolbarHeight, Math.min(newY, 0))); } }
3. 几个注意点
- 确保你的可滚动View(比如
RecyclerView)是NestedScrollingChild,如果是旧的ListView,要添加android:nestedScrollingEnabled="true"属性 - 如果想要更平滑的折叠动画,可以在
onNestedPreScroll里结合属性动画来调整偏移量,替换直接设置y值的方式 - 第一个Toolbar不要设置任何
scrollFlags或滚动Behavior,保持默认固定即可
内容的提问来源于stack exchange,提问作者Andrew
相关产品推荐
相关产品推荐

