Запретить увольнение нижнего листаDialogFragment при касании снаружи

Я реализовал диалоговое окно 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);
    }
}

В соответствии со спецификацией BottomSheet нижние листы можно отклонить, коснувшись внешней стороны нижнего листа, поэтому, каковы мои варианты, чтобы отменить это поведение и предотвратить его отклонение?

Ответ 1

Вы должны использовать #setCancelable(false) при создании экземпляра.

    BottomSheetDialogFragment bottomSheetDialogFragment = new SequenceControlFragmentBottomSheet();
    bottomSheetDialogFragment.setCancelable(false);
    bottomSheetDialogFragment.show(getChildFragmentManager(), bottomSheetDialogFragment.getTag());

Ответ 2

setCancelable(false) также предотвратит отклонение нижнего листа при setCancelable(false) нажатии. Если мы посмотрим на ресурс макета для нижнего листа в библиотеке поддержки дизайна Android, то есть компонент View с идентификатором touch_outside и OnClickListener установленный в методе wrapInBottomSheet объекта BottomSheetDialog, который используется для обнаружения внешних нажатий и закрытия диалогового окна. Таким образом, чтобы предотвратить отмену при касании за пределами нижнего листа, нам нужно удалить OnClickListener.

Добавьте эти строки в метод onActivityCreated (или любой другой метод жизненного цикла после onCreateView).

@Override public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    View touchOutsideView = getDialog().getWindow()
        .getDecorView()
        .findViewById(android.support.design.R.id.touch_outside);
    touchOutsideView.setOnClickListener(null);
}

Также, если вы хотите предотвратить отклонение нижнего листа, проведя вниз, измените поведение диалогового окна нижнего листа Hideable false. Для setHideable(false) добавьте следующий код в метод onCreateDialog.

@Override public Dialog onCreateDialog(Bundle savedInstanceState) {
    final BottomSheetDialog bottomSheetDialog =
        (BottomSheetDialog) super.onCreateDialog(savedInstanceState);

    bottomSheetDialog.setOnShowListener(new DialogInterface.OnShowListener() {
      @Override public void onShow(DialogInterface dialog) {
        FrameLayout bottomSheet =
        bottomSheetDialog.findViewById(android.support.design.R.id.design_bottom_sheet);

        if (null != bottomSheet) {
          BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);
        behavior.setHideable(false);
        }
      }
    });
    return bottomSheetDialog;
  }

Ответ 3

Ответ от М. Erfan Mowlaei полезен, но я искал способ применить это поведение каждый раз, когда создается экземпляр класса без необходимости вызывать setCancelable(false). Смотрите ниже.

class MyBottomSheet : BottomSheetDialogFragment() {

companion object {
    fun newInstance() = MyBottomSheet().apply {
        isCancelable = false
      }
   }
}