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

Android:设置HideBottomViewOnScrollBehavior后Fab无法随Snackbar上移

解决方案:同时保留Fab滚动隐藏与Snackbar联动效果

问题根源

给Fab设置HideBottomViewOnScrollBehavior后,该Behavior默认未处理Snackbar的位移事件,导致Fab不会随Snackbar上移;另外错误地将Fab嵌套在FrameLayout内,破坏了CoordinatorLayout对子View的Behavior管理能力。


步骤1:修正布局结构

将Fab从FrameLayout中移出,直接作为CoordinatorLayout的子View,确保CoordinatorLayout能正确处理其Behavior和与Snackbar的联动:

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/content_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".presentation.features.lead.list.LeadsListFragment">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recycler_leads"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layoutAnimation="@anim/slide_in_animation"
            android:orientation="vertical"
            android:visibility="gone"
            tools:itemCount="6"
            tools:listitem="@layout/item_lead" />

        <ProgressBar
            android:id="@+id/spinner_recycler"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:indeterminateTint="@color/link"
            android:indeterminateTintMode="src_atop" />

        <TextView
            android:id="@+id/message_error"
            style="@style/TextAppearance.RecyclerViewMessage"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginHorizontal="24dp"
            android:text="@string/message_internal_error"
            android:visibility="gone"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/message_empty_list"
            style="@style/TextAppearance.RecyclerViewMessage"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginHorizontal="24dp"
            android:text="@string/message_no_lead_added"
            android:visibility="gone"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </FrameLayout>

    <!-- Fab直接作为CoordinatorLayout子View -->
    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/add_fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="16dp"
        android:contentDescription="@string/fab_add_lead_desc"
        android:scaleX="0"
        android:scaleY="0"
        android:visibility="invisible"
        app:backgroundTint="@color/colorPrimary"
        app:layout_behavior=".presentation.features.lead.list.ScrollHideFabWithSnackbarBehavior"
        app:srcCompat="@drawable/ic_add"
        app:tint="@android:color/white" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>

步骤2:自定义Behavior继承HideBottomViewOnScrollBehavior

重写方法处理Snackbar的位移事件,让Fab随Snackbar上移:

import com.google.android.material.behavior.HideBottomViewOnScrollBehavior
import com.google.android.material.snackbar.Snackbar
import android.view.View

class ScrollHideFabWithSnackbarBehavior : HideBottomViewOnScrollBehavior<View>() {

    override fun layoutDependsOn(parent: androidx.coordinatorlayout.widget.CoordinatorLayout, child: View, dependency: View): Boolean {
        // 判断依赖是否为Snackbar的View
        return dependency is Snackbar.SnackbarLayout || super.layoutDependsOn(parent, child, dependency)
    }

    override fun onDependentViewChanged(parent: androidx.coordinatorlayout.widget.CoordinatorLayout, child: View, dependency: View): Boolean {
        val result = super.onDependentViewChanged(parent, child, dependency)
        if (dependency is Snackbar.SnackbarLayout) {
            // 调整Fab的Y轴位置,跟随Snackbar上移
            val translationY = Math.min(0f, dependency.translationY - dependency.height)
            child.translationY = translationY
        }
        return result
    }
}

步骤3:正确显示Snackbar

将Snackbar的锚点设置为Fab,确保两者联动:

Snackbar.make(binding.contentView, R.string.permission_needed, Snackbar.LENGTH_LONG)
    .setAnchorView(binding.addFab)
    .show()

关键说明

  • 必须让Fab作为CoordinatorLayout的直接子View,否则CoordinatorLayout无法协调其与Snackbar的联动。
  • 自定义Behavior既保留了HideBottomViewOnScrollBehavior的滚动隐藏逻辑,又新增了Snackbar位移的处理,实现两种效果并存。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 19:54:56