【问题标题】:BottomSheetDialogFragment - How to set expanded height (or min top offset)BottomSheetDialogFragment - 如何设置扩展高度(或最小顶部偏移)
【发布时间】:2025-12-01 01:05:01
【问题描述】:

我创建了一个BottomSheetDialogFragment,我想调整它的最大展开高度。我怎样才能做到这一点?我可以检索BottomSheetBehaviour,但我能找到的只是窥视高度的设置器,而扩展高度则没有。

public class DialogMediaDetails extends BottomSheetDialogFragment
{
    @Override
    public void setupDialog(Dialog dialog, int style)
    {
        super.setupDialog(dialog, style);
        View view = View.inflate(getContext(), R.layout.dialog_media_details, null);
        dialog.setContentView(view);

        ...

        View bottomSheet = dialog.findViewById(R.id.design_bottom_sheet);
        BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);
        behavior.setPeekHeight(...);
        // how to set maximum expanded height???? Or a minimum top offset?

    }
}

编辑

我为什么需要它?因为我在全屏活动中显示了一个BottomSheet 对话框,如果BottomSheet 在顶部留下一个空格,它看起来很糟糕......

【问题讨论】:

  • 我很想知道如何为`modal bottom sheet`设置max height。我需要我的模态底部工作表只到半屏,即使在拖动后也永远不会到顶部......有任何线索吗?
  • @abat 希望对您有所帮助:*.com/a/53791225/1318946
  • @eRaisedToX 你也可以试试:*.com/a/53791225/1318946

标签: android android-support-library androiddesignsupport bottom-sheet


【解决方案1】:

高度被包裹,因为膨胀的视图被添加到具有layout_height=wrap_content 的 FrameLayout 中。请参阅 https://github.com/dandar3/android-support-design/blob/master/res/layout/design_bottom_sheet_dialog.xml 上的 FrameLayout (R.id.design_bottom_sheet)。

下面的类使底部工作表全屏,背景透明,并完全展开到顶部。

public class FullScreenBottomSheetDialogFragment extends BottomSheetDialogFragment {


    @CallSuper
    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        ButterKnife.bind(this, view);
    }


    @Override
    public void onStart() {
        super.onStart();
        Dialog dialog = getDialog();

        if (dialog != null) {
            View bottomSheet = dialog.findViewById(R.id.design_bottom_sheet);
            bottomSheet.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;
        }
        View view = getView();
        view.post(() -> {
            View parent = (View) view.getParent();
            CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) (parent).getLayoutParams();
            CoordinatorLayout.Behavior behavior = params.getBehavior();
            BottomSheetBehavior bottomSheetBehavior = (BottomSheetBehavior) behavior;
            bottomSheetBehavior.setPeekHeight(view.getMeasuredHeight());
            ((View)bottomSheet.getParent()).setBackgroundColor(Color.TRANSPARENT)

        });
    }

}

--- 编辑 2018 年 8 月 30 日 --- 一年后,我意识到背景在错误的视图上着色。当用户拖动对话框时,这会将背景与内容一起拖动。 我修复了它,以便底部工作表的父视图是彩色的。

【讨论】:

  • 与androidX一起使用:dialog?.findViewById<View>( com.google.android.material.R.id.design_bottom_sheet )
  • 有人能解释一下为什么在onCreateDialogonViewCreated 中查找底部工作表视图似乎不起作用吗?
  • View bottomSheet = dialog.findViewById(R.id.design_bottom_sheet); bottomSheet.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT; 这就是我要找的
【解决方案2】:

我找到了一个更简单的答案;在您的示例中,您使用此代码获取底部工作表的 FrameLayout

View bottomSheet = dialog.findViewById(R.id.design_bottom_sheet);

然后,您可以将该视图的布局参数上的高度设置为您希望将展开高度设置为的任何高度。

bottomSheet.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;

【讨论】:

  • 与androidX一起使用:dialog?.findViewById<View>( com.google.android.material.R.id.design_bottom_sheet )
  • 我注意到的一件事,只有当我们的底页的父布局是RelativeLayout时才有效
【解决方案3】:

重大更新 避免重复代码我提供了一个指向 full answer 的链接,您可以在其中找到有关如何获得 Google 地图等完整行为的所有说明。


我想调整它的最大展开高度。我该怎么做?

BottomSheetBottomSheetDialogFragment 都使用您可以在支持库 23.x 中找到的 BottomSheetBehavior

Java 类对mMinOffset 有两种不同的用途,其中一种用于定义父级的区域,它将用于绘制其内容(可能是NestedScrollView)。另一个用途是定义扩展的锚点,我的意思是,如果你向上滑动它以形成STATE_COLLAPSED它会为你的BottomSheet设置动画,直到他到达这个锚点但是如果你仍然可以继续向上滑动以覆盖所有父级高度(CoordiantorLayout 高度)。

如果你看一下BottomSheetDialog,你会看到这个方法:

private View wrapInBottomSheet(int layoutResId, View view, ViewGroup.LayoutParams params) {
    final CoordinatorLayout coordinator = (CoordinatorLayout) View.inflate(getContext(),
            android.support.design.R.layout.design_bottom_sheet_dialog, null);
    if (layoutResId != 0 && view == null) {
        view = getLayoutInflater().inflate(layoutResId, coordinator, false);
    }
    FrameLayout bottomSheet = (FrameLayout) coordinator.findViewById(android.support.design.R.id.design_bottom_sheet);
    BottomSheetBehavior.from(bottomSheet).setBottomSheetCallback(mBottomSheetCallback);
    if (params == null) {
        bottomSheet.addView(view);
    } else {
        bottomSheet.addView(view, params);
    }
    // We treat the CoordinatorLayout as outside the dialog though it is technically inside
    if (shouldWindowCloseOnTouchOutside()) {
        final View finalView = view;
        coordinator.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (isShowing() &&
                        MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_UP &&
                        !coordinator.isPointInChildBounds(finalView,
                                (int) event.getX(), (int) event.getY())) {
                    cancel();
                    return true;
                }
                return false;
            }
        });
    }
    return coordinator;
}



不知道您想要这两种行为中的哪一种,但如果您需要第二种行为,请按照以下步骤操作:

  1. 创建一个 Java 类并从 CoordinatorLayout.Behavior<V> 扩展它

  2. 将默认BottomSheetBehavior 文件中的粘贴代码复制到您的新文件中。

  3. 用以下代码修改方法clampViewPositionVertical

    @Override
    public int clampViewPositionVertical(View child, int top, int dy) {
        return constrain(top, mMinOffset, mHideable ? mParentHeight : mMaxOffset);
    }
    int constrain(int amount, int low, int high) {
        return amount < low ? low : (amount > high ? high : amount);
    }
    
  4. 添加新状态

    public static final int STATE_ANCHOR_POINT = X;
    
  5. 修改下一个方法:onLayoutChildonStopNestedScrollBottomSheetBehavior&lt;V&gt; from(V view)setState(可选)

这是它的样子
[]

【讨论】:

  • 这是一个很好的解决方案!感谢您提供完整的答案 Miguel
【解决方案4】:

它对我有用。在 BottomSheetDialogFragment 的 onViewCreated() 方法上添加代码

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    view.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
        override fun onGlobalLayout() {

            view.viewTreeObserver.removeOnGlobalLayoutListener(this)

            val dialog = dialog as BottomSheetDialog
            val bottomSheet = dialog.findViewById<View>(com.google.android.material.R.id.design_bottom_sheet) as FrameLayout?
            val behavior = BottomSheetBehavior.from(bottomSheet!!)
            behavior.state = BottomSheetBehavior.STATE_EXPANDED

            val newHeight = activity?.window?.decorView?.measuredHeight
            val viewGroupLayoutParams = bottomSheet.layoutParams
            viewGroupLayoutParams.height = newHeight ?: 0
            bottomSheet.layoutParams = viewGroupLayoutParams
        }
    })
    dialogView = view
}

别忘了删除 viewTreeObserver。

override fun onDestroyView() {
    dialogView?.viewTreeObserver?.addOnGlobalLayoutListener(null)
    super.onDestroyView()
}

【讨论】:

  • 使用addOnGlobalLayoutListener会导致闪屏,主逻辑在onViewCreated中可以合法
  • 我注意到的一件事是,decorview 也在考虑导航视图高度,因此在替换活动?使用 displaymetrics 的像素,对我有用
【解决方案5】:

科特林

在我的情况下,我需要定义一个固定的高度,我做了以下操作:

val bottomSheet: View? = dialog.findViewById(R.id.design_bottom_sheet)
BottomSheetBehavior.from(bottomSheet!!).peekHeight = 250

这样您还可以访问BottomSheetBehavior 的任何属性,例如halfExpandedRatio

【讨论】:

    【解决方案6】:

    我建议不要使用 id 来查找视图。在BottomSheetFragmentDialog 中,对话框是BottomSheetDialog,它公开了底部工作表的行为。您可以使用它来设置窥视高度。

    (dialog as BottomSheetDialog).behavior.peekHeight = ...
    

    【讨论】:

      【解决方案7】:

      获取工作表行为的参考,

      private val behavior by lazy { (dialog as BottomSheetDialog).behavior }
      

      关闭fitToContents 并将expandedOffset 设置为所需的像素。

      behavior.isFitToContents = false
      behavior.expandedOffset = 100
      

      【讨论】: