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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 07:43:32