求助:实现随Bottom Sheet Fragment联动的悬浮按钮
我来帮你搞定这个FAB和Bottom Sheet同步移动的需求,就像Google Maps里那样!之前把FAB放进Bottom Sheet布局里的思路确实有问题,咱们换个更靠谱的方案——利用CoordinatorLayout的特性来实现视图间的联动,这样既不会让FAB跟着Bottom Sheet消失,也能保证它在任何状态下都正常显示。
第一步:调整布局结构
首先,把FAB改成CoordinatorLayout的直接子View,不要锚定到conteudo容器,也别放进Bottom Sheet里。这样FAB的生命周期就独立于Bottom Sheet,不会跟着它一起隐藏:
<android.support.design.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:layout_width="match_parent" android:layout_height="match_parent" tools:context="br.com.vix.v1motorista.MotoristaActivity"> <!-- 地图容器 --> <FrameLayout android:id="@+id/conteudo" android:layout_width="match_parent" android:layout_height="match_parent" /> <!-- 悬浮按钮:作为CoordinatorLayout的直接子View --> <android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|end" android:layout_margin="@dimen/fab_margin" android:visibility="visible" app:srcCompat="@drawable/ic_info_white_36dp" /> <!-- Bottom Sheet --> <include android:id="@+id/pickUpFragment" layout="@layout/fragment_pax_pick_up_2" /> </android.support.design.widget.CoordinatorLayout>
第二步:实现联动逻辑(两种方案可选)
方案一:用BottomSheetCallback监听滑动(简单直接)
在你的Activity里,获取Bottom Sheet的BottomSheetBehavior,然后设置滑动回调,根据Bottom Sheet的偏移量调整FAB的位置:
// 获取Bottom Sheet视图 View bottomSheet = findViewById(R.id.pickUpFragment); BottomSheetBehavior<View> bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet); FloatingActionButton fab = findViewById(R.id.fab); // 设置滑动回调 bottomSheetBehavior.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { @Override public void onStateChanged(@NonNull View bottomSheet, int newState) { // 当Bottom Sheet完全隐藏时,让FAB回到初始位置 if (newState == BottomSheetBehavior.STATE_HIDDEN) { fab.setTranslationY(0); } } @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { // slideOffset范围:0(完全隐藏)→ 1(完全展开) int bottomSheetHeight = bottomSheet.getHeight(); // 计算FAB需要向上移动的距离:偏移量 × Bottom Sheet高度(负数表示向上移) float fabTranslationY = -slideOffset * bottomSheetHeight; fab.setTranslationY(fabTranslationY); } }); // 初始化FAB位置(如果Bottom Sheet默认是Peek状态) int peekHeight = bottomSheetBehavior.getPeekHeight(); if (peekHeight > 0) { int bottomSheetHeight = bottomSheet.getHeight(); float initialOffset = (float) peekHeight / bottomSheetHeight; fab.setTranslationY(-initialOffset * bottomSheetHeight); }
方案二:自定义CoordinatorBehavior(更优雅,解耦逻辑)
如果不想把逻辑写在Activity里,可以自定义一个Behavior,把联动逻辑封装进去,这样布局和代码更清晰:
- 创建自定义Behavior类:
public class FabBottomSheetBehavior extends CoordinatorLayout.Behavior<FloatingActionButton> { public FabBottomSheetBehavior(Context context, AttributeSet attrs) { super(context, attrs); } // 声明FAB依赖Bottom Sheet视图 @Override public boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionButton child, View dependency) { return dependency.getId() == R.id.pickUpFragment; } // 当依赖的Bottom Sheet位置变化时,调整FAB位置 @Override public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton child, View dependency) { BottomSheetBehavior<?> behavior = BottomSheetBehavior.from(dependency); float slideOffset = behavior.getSlideOffset(); int bottomSheetHeight = dependency.getHeight(); child.setTranslationY(-slideOffset * bottomSheetHeight); return true; } }
- 在布局里给FAB设置这个Behavior:
<android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|end" android:layout_margin="@dimen/fab_margin" android:visibility="visible" app:layout_behavior=".FabBottomSheetBehavior" <!-- 这里设置自定义Behavior --> app:srcCompat="@drawable/ic_info_white_36dp" />
为什么之前的方法不行?
把FAB放进Bottom Sheet的布局里,相当于把它变成了Bottom Sheet的子View:
- 当Bottom Sheet关闭(隐藏)时,FAB会跟着父View一起被隐藏
- 当Bottom Sheet处于部分隐藏状态时,FAB会被Bottom Sheet的布局边界限制,无法完全显示出来
而咱们上面的方案,让FAB独立于Bottom Sheet,通过监听Bottom Sheet的滑动来主动调整位置,完美解决这两个问题。
内容的提问来源于stack exchange,提问作者David Rocha
相关产品推荐
相关产品推荐

