防止点击外部区域关闭 BottomSheetDialogFragment

67
我已经实现了一个BottomSheet对话框,并且希望当用户在peeking状态(未完全展开状态)下触摸底部之外的区域时,防止bottomsheet关闭。
我已经在代码中设置了 dialog.setCanceledOnTouchOutside(false);,但似乎没有任何效果。
这是我的BottomSheetDialogFragment类:
public class ShoppingCartBottomSheetFragment extends BottomSheetDialogFragment  {

    private BottomSheetBehavior.BottomSheetCallback mBottomSheetBehaviorCallback = new BottomSheetBehavior.BottomSheetCallback() {

        @Override
        public void onStateChanged(@NonNull View bottomSheet, int newState) {
            if (newState == BottomSheetBehavior.STATE_HIDDEN) {
                dismiss();
            }

        }

        @Override
        public void onSlide(@NonNull View bottomSheet, float slideOffset) {
        }
    };

    @Override
    public void setupDialog(Dialog dialog, int style) {
        super.setupDialog(dialog, style);

        View contentView = View.inflate(getContext(), R.layout.fragment_shopping_cart_bottom_sheet, null);

        dialog.setCanceledOnTouchOutside(false);

        dialog.setContentView(contentView);

        CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) ((View) contentView.getParent()).getLayoutParams();
        CoordinatorLayout.Behavior behavior = params.getBehavior();

        if( behavior != null && behavior instanceof BottomSheetBehavior ) {
            ((BottomSheetBehavior) behavior).setBottomSheetCallback(mBottomSheetBehaviorCallback);
            ((BottomSheetBehavior) behavior).setPeekHeight(97);
            ((BottomSheetBehavior) behavior).setHideable(false);
        }
    }


    @Override
    public void onStart() {
        super.onStart();
        Window window = getDialog().getWindow();
        WindowManager.LayoutParams windowParams = window.getAttributes();
        windowParams.dimAmount = 0;
        windowParams.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
        window.setAttributes(windowParams);
    }
}

根据底部工作表规范,可以通过触摸底部工作表外部来关闭底部工作表,那么我有哪些选项可以覆盖此行为并防止其被关闭?
13个回答

1
简单而简短的工作解决方案。
    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        getDialog().setCanceledOnTouchOutside(false);
    }

在您的customDialogFragment中覆盖BottomSheetDialogFragment的onActivityCreated()方法,并设置setCanceledOnTouchOutside(false)。

1
我认为以上所有答案都有些不够完整,我将解释原因。
  1. setCancelable会阻止外部点击行为,但也会阻止你的BottomSheetDialogFragment从后退键返回。
  2. 一些答案正在覆盖setCancelable()方法以管理外部点击,这有点复杂,因为你需要处理可取消和可隐藏。
解决方案
override fun onStart() {
       super.onStart()
       stopOutsideClick()
}

private fun stopOutsideClick() {
       val touchOutsideView = dialog?.window?.decorView?.findViewById<View>(com.google.android.material.R.id.touch_outside)
       touchOutsideView?.setOnClickListener(null)
}

您需要在onStart()中调用此方法,其中对话框实例将始终存在。


这是一个非常好的拦截BottomSheet关闭的方法,如果您想验证一些数据或在关闭之前询问用户是否真的想要退出,则可以使用它。 - JU5T1C3

0

我遇到了同样的问题。但是我需要防止底部片段通过点击外部关闭,而留下向下滑动关闭的机会。只需在BSFragment类中添加变量isHideable: Boolean并添加以下代码片段即可

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    val dialog = super.onCreateDialog(savedInstanceState)
    dialog.setOnShowListener {
        val d = dialog as BottomSheetDialog
        val bottomSheet =
            d.findViewById<FrameLayout>(com.google.android.material.R.id.design_bottom_sheet)
        BottomSheetBehavior.from(bottomSheet!!).state = initialState()
        BottomSheetBehavior.from(bottomSheet).setHideable(isHideable)
    }
    return dialog
}

当你调用碎片时 - 将 isHideable 设置为 true

private fun showBSFragmentDialog() {
  val bSFDialog = BSFragment.newInstance()
  bSFDialog.isCancelable = false
  bSFDialog.isHideable = true
  bSFDialog.show(supportFragmentManager, "bSFDialog")  }

现在用户无法通过点击外部来关闭它,但可以向下滑动并关闭对话框。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接