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
相关产品推荐
相关产品推荐

