8

Is it possible to disable dragging for a BottomSheetDialogFragment, containing scrollable views such as a ViewPager or a NestedScrollView, such that it can't be dragged neither up nor down but still be dismissed by touching outside and that the children can be dragged anyways?

I've looked at all the answers here but I am not pleased since most don't take into account scrollable children or work by forcing the expanded state. The closest is this answer but nonetheless allows dragging the sheet up.

Is there any solution or at least guidance at what should I modify of the original source code?

OneEyeQuestion
  • 742
  • 7
  • 22

1 Answers1

18

If you debug your application and use Layout Inspector tool, you will see that BottomSheetDialogFragment uses CoordinatorLayout. Dimmed background is a simple view with an OnClickListener that closes the dialog, and sheet movement is driven by CoordinatorLayout.Behavior.

This can be overriden by modifying created dialog:

Java:

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    final Dialog d = super.onCreateDialog(savedInstanceState);
    // view hierarchy is inflated after dialog is shown
    d.setOnShowListener(new DialogInterface.OnShowListener() {
        @Override
        public void onShow(DialogInterface dialogInterface) {
            //this disables outside touch
            d.getWindow().findViewById(R.id.touch_outside).setOnClickListener(null);
            //this prevents dragging behavior
            View content = d.getWindow().findViewById(R.id.design_bottom_sheet);
            ((CoordinatorLayout.LayoutParams) content.getLayoutParams()).setBehavior(null);
        }
    });
    return d;
}

Kotlin:

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    val d = super.onCreateDialog(savedInstanceState)
    //view hierarchy is inflated after dialog is shown
    d.setOnShowListener {
        //this disables outside touch
        d.window.findViewById<View>(R.id.touch_outside).setOnClickListener(null)
        //this prevents dragging behavior
        (d.window.findViewById<View>(R.id.design_bottom_sheet).layoutParams as CoordinatorLayout.LayoutParams).behavior = null
    }
    return d
}

This does use internal IDs of design library, but unless for some reason they're changed this should be stable.

Pawel
  • 15,548
  • 3
  • 36
  • 36
  • I had an error in the redaction of my question. Sorry. I still want to be able to dismiss with click. Anyways, what you propose wouldn't also eliminate the dragging of potential children? – OneEyeQuestion Jan 21 '18 at 01:04
  • Don't override `R.id.touch_outside` `OnClickListener` to keep dismiss on click. I tried with nested scroll view and it was scrolling fine while bottom sheet kept its initial height. – Pawel Jan 21 '18 at 11:00
  • I just tested your solution but without the behavior the bottom sheet fully expanded to cover all the screen. I tried using peek height but didn't work. How did you control the initial height? – OneEyeQuestion Jan 21 '18 at 18:40
  • 2
    You could override more layout params of `R.id.design_bottom_sheet` to include gravity bottom and layout_height of wrap_content, but at that point I'm starting to wonder if you should just create a regular DialogFragment with bottom gravity and slide in/out animations since you don't use core functionality of sheet which is nested scrolling, dragging and snapping. – Pawel Jan 21 '18 at 20:28
  • My layout_height is around 500dp. Using your method, there is a transparent space at the bottom, which is think the remaining height i.e rootlayoutht - ht.ofbottomsheet. And it looks horrible. What to do? – Aman Verma Jun 04 '19 at 04:40
  • This will throw `IllegalArgumentException` if you call `dismiss()` in material comp. v1.1.0-alpha10 – Jemshit Sep 21 '19 at 12:27
  • `The view is not associated with BottomSheetBehavior`. Thrown when called `dismiss()`. There are other bugs in v1.1.0-alpha10, so maybe this is one of them. Probably here: https://github.com/material-components/material-components-android/blob/master/lib/java/com/google/android/material/bottomsheet/BottomSheetBehavior.java#L1435 – Jemshit Sep 21 '19 at 13:53
  • @JemshitIskenderov I'm not sure if is can be considered a bug since it looks like just force checks if bottom sheet has valid behavior. So it will obviously not account for this "hack" of removing the behavior object. I think at this point we'll need to replace `BottomSheetBehavior` with a custom one that does not handle/intercept touch events. – Pawel Sep 21 '19 at 14:02
  • Worked like a charm! I am using a BottomSheetDialogFragment with a nestedScrollView inside. – renatoarg Nov 21 '19 at 22:55