Disabling User dragging on BottomSheet
Asked Answered
T

37

129

I am trying to disable user dragging on BottomSheet. The reason I want to disable is two things. 1. It's preventing the ListView from scrolling downward, 2. I don't want users to dismiss using dragging but with a button on the BottomSheetView. This is what I've done

 bottomSheetBehavior = BottomSheetBehavior.from(bottomAnc);
    bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
        @Override
        public void onStateChanged(@NonNull View bottomSheet, int newState) {
            if (newState == BottomSheetBehavior.STATE_EXPANDED) {
                //Log.e("BottomSheet", "Expanded");
            } else if (newState == BottomSheetBehavior.STATE_COLLAPSED) {
                //Log.e("BottomSheet", "Collapsed");
            }
        }

        @Override
        public void onSlide(@NonNull View bottomSheet, float slideOffset) {
            // React to dragging events
            bottomSheet.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    int action = MotionEventCompat.getActionMasked(event);
                    switch (action) {
                        case MotionEvent.ACTION_DOWN:
                            return false;
                        default:
                            return true;
                    }
                }
            });
        }
    });

The bottomSheetLayout

    <?xml version="1.0" encoding="utf-8"?><FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
app:behavior_hideable="true"
app:behavior_peekHeight="0dp"
app:layout_behavior="@string/bottom_sheet_behavior"
android:id="@+id/bottomSheet">

<android.support.v7.widget.CardView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:elevation="10dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:gravity="center_vertical">

            <TextView
                android:id="@+id/text1"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="Order Items"
                android:layout_margin="16dp"
                android:textAppearance="@android:style/TextAppearance.Large"/>


            <Button
                android:layout_width="50dp"
                android:layout_height="wrap_content"
                android:layout_marginRight="5dp"
                android:background="@drawable/bg_accept"/>

            <Button
                android:layout_width="50dp"
                android:layout_height="wrap_content"
                android:layout_marginRight="8dp"
                android:background="@drawable/bg_cancel"/>

        </LinearLayout>

        <ListView
            android:id="@+id/item_edit"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/white"
            android:divider="@color/md_divider_black"
            android:dividerHeight="1dp"/>

    </LinearLayout>

</android.support.v7.widget.CardView>

Temperance answered 4/3, 2016 at 10:56 Comment(0)
H
106

It can be now no longer relevant, but I will leave it here:

import android.content.Context
import android.util.AttributeSet
import androidx.coordinatorlayout.widget.CoordinatorLayout
import android.view.MotionEvent
import android.view.View
import com.google.android.material.bottomsheet.BottomSheetBehavior

@Suppress("unused")
class LockableBottomSheetBehavior<V : View> : BottomSheetBehavior<V> {
    constructor() : super()
    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)

    var swipeEnabled = true

    override fun onInterceptTouchEvent(
        parent: CoordinatorLayout,
        child: V,
        event: MotionEvent
    ): Boolean {
        return if (swipeEnabled) {
            super.onInterceptTouchEvent(parent, child, event)
        } else {
            false
        }
    }

    override fun onTouchEvent(parent: CoordinatorLayout, child: V, event: MotionEvent): Boolean {
        return if (swipeEnabled) {
            super.onTouchEvent(parent, child, event)
        } else {
            false
        }
    }

    override fun onStartNestedScroll(
        coordinatorLayout: CoordinatorLayout,
        child: V,
        directTargetChild: View,
        target: View,
        axes: Int,
        type: Int
    ): Boolean {
        return if (swipeEnabled) {
            super.onStartNestedScroll(
                coordinatorLayout,
                child,
                directTargetChild,
                target,
                axes,
                type
            )
        } else {
            false
        }
    }

    override fun onNestedPreScroll(
        coordinatorLayout: CoordinatorLayout,
        child: V,
        target: View,
        dx: Int,
        dy: Int,
        consumed: IntArray,
        type: Int
    ) {
        if (swipeEnabled) {
            super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type)
        }
    }

    override fun onStopNestedScroll(
        coordinatorLayout: CoordinatorLayout,
        child: V,
        target: View,
        type: Int
    ) {
        if (swipeEnabled) {
            super.onStopNestedScroll(coordinatorLayout, child, target, type)
        }
    }

    override fun onNestedPreFling(
        coordinatorLayout: CoordinatorLayout,
        child: V,
        target: View,
        velocityX: Float,
        velocityY: Float
    ): Boolean {
        return if (swipeEnabled) {
            super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY)
        } else {
            false
        }
    }
}

And use it in your xml file:

app:layout_behavior="com.your.package.LockableBottomSheetBehavior"

It disables all users actions, it can be used when you want control BottomSheet only programmatically.

Hockey answered 6/10, 2016 at 9:47 Comment(19)
This is the best answer, for disabling BottomSheetBehaviour. A man above also posted similiar solution, but he didn't write to override others event like onTouchEvent(). In other hand you may improve your answer if you put a flag instead of falseLogician
@murt, thanks. I posted this because in some cases other answers give me wrong behavior. Only if override all method we can obtain useful result. I think that who needs the flag can easy add it :)Hockey
@ВиталийОбидейко this is great! thank you! i tried all answer. Only this worked. Thanks a lot!Merozoite
How do you use this with a BottomSheetFragment ?Stable
You need to specifically refer to this class in your XML. app:layout_behavior="com.my.package.UserLockBottomSheetBehavior"Interglacial
In some cases, this still doesn't work, if we have a list in bottom sheet fragment, it still dragsAsthmatic
@DeepakJoshi this solution was for static content. Need to look into scrollable content problemHockey
@DeepakJoshi what did you use Recycler or smth else?Hockey
@ВиталийОбидейко, Yes, I used recycler view and when I try to scroll down on the area where recycler view is there, the parent bottom sheet also starts dragging.Asthmatic
@DeepakJoshi I think it is because of developer.android.com/reference/android/support/v7/widget/… implements developer.android.com/reference/android/support/v4/view/…. But how u could fix it I can't suggest right nowHockey
@DeepakJoshi maybe u may extends of RecyclerView and override few methods like 'hasNestedScrollingParent', but I am not sureHockey
@ВиталийОбидейко, thanks for the quick reply, currently I have changed the approach, but I will surely try this.Asthmatic
@DeepakJoshi You might have certainly used SwipeRefreshLayout. Exclude that and bottom sheet won't be dragging down on RecyclerView up scroll.Dudley
@Debdeep, I was using RecyclerView, now I have changed my use case.Asthmatic
setBottomSheetCallback is deprecated API 28 not working crashingTache
this works if you set var swipeEnabled = false for recyclerview in bottomsheet as well.Dahl
Very solutions. But not sure why it did not work for me. Any thoughts @VitaliiObideiko I am using Viewpager with recyclerView. :(Gunk
@VitaliiObideiko how to change swipeEnabled value dynamically ?Sauger
@NiravJoshi just add public method where you may set value to itHockey
S
86

EDIT 22-05-2023

Please use addBottomSheetCallback instead setBottomSheetCallback

Thanks, @abedullah


check the state in onStateChanged method of setBottomSheetCallback if state is BottomSheetBehavior.STATE_DRAGGING then change it to BottomSheetBehavior.STATE_EXPANDED this way you can stop STATE_DRAGGING by user. like below

final BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);
        behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
            @Override
            public void onStateChanged(@NonNull View bottomSheet, int newState) {
                if (newState == BottomSheetBehavior.STATE_DRAGGING) {
                    behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
                }
            }

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

use button to open close bottom sheet like below

fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (behavior.getState() == BottomSheetBehavior.STATE_HIDDEN) {
                    behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
                } else {
                    behavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
                }
            }
        });

don't use setPeekHeight or app:behavior_peekHeight

by above way you can reach your goal

Sarnen answered 4/3, 2016 at 11:19 Comment(20)
Nice trick. Didn't notice that. Thanks. And also, can you help with this. When I tell it to expand at first, it's transparent and I can see the view behind, but I can't interact not until I tap on the EditText in the SheetView before making it visible.Temperance
I made my BottomSheet View match_parent and whenever I try to bring it up in my Activity I noticed it slides up, but it's not visible not until I tap the EditText in it which brings up the Keyboard and make the BottomSheet View visibleTemperance
Yeah. It's like it's active but totally transparent and not visible but responds to touch.Temperance
for this you need bottom sheet layout have more content other wise its not show you as match_parent. I don't think its work as what you want.Sarnen
I tried this, but the states ends up in STATE_SETTLING. I have a button to open and close bottom sheet, if it is HIDDEN, I expand it. If it is EXPANDED, I hide it. Since it gets stuck in SETTLING, my button doesn't work after dragging bottom sheet. Any idea on that?Superheat
This solution is unreliable; the bottom sheet gets into a bad state, as Gokhan said... and when in that bad state, calls like loading a new fragment into the bottom sheet will simply blank out.Sinless
this also seems to be helpful: https://mcmap.net/q/175435/-scrolling-issue-with-bottomsheet-androidShondrashone
This works for persistent bottom sheets of mine but is not working for modal bottom sheets..Any idea why?Iridissa
It worked for me. Thanks, But little bit doubt about that Is it correct way?Macknair
there is not correct way to do something. whatever work for you choose it. and be prepare to change.Sarnen
It will not work if you have nestedscrollview inside bottom sheetRilke
this trick is somewhat irrelevant if user experience is concerned, as it makes the bottom sheet behaviour abnormal. The sheet collapses when user taps anywhere .when the sheet's state is : ExpandedExcrete
What is the negative effect of using setPeekHeight ? I have set behavior.peekHeight = Int.MAX_VALUE and it's working for me. I am not sure if it has any side effects.Rhyton
@RishabhChandel did you find the solution yet?Tache
it doesn't work with NestedScrollView @RishabhChandel you saved my day! Many thanks!!!Fix
In case of netstedscrollview, also set isNestedScrollingEnabledto falseBrew
This method does not work if you are using nestedscrollview, It is working with Scrollview.Armistice
This worked perfect for me. Thank you!Sonora
it works perfect but setBottomSheetCallback depreciated! please use addBottomSheetCallback Alexandretta
behavior.isDraggable = falseDrawback
M
65
implementation 'com.google.android.material:material:1.2.0-alpha05'

you can disable dragging the BottomSheet like this.

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    val dialog = BottomSheetDialog(requireContext(), theme)
    dialog.setOnShowListener {
        setBottomSheetExpanded(dialog)
    }
    return dialog
}

open fun setBottomSheetExpanded(bottomSheetDialog: BottomSheetDialog) {
    val bottomSheet =
        bottomSheetDialog.findViewById<View>(R.id.design_bottom_sheet) as FrameLayout?
    bottomSheet?.let {
        val behavior: BottomSheetBehavior<*> = BottomSheetBehavior.from(bottomSheet)
        val layoutParams = bottomSheet.layoutParams
        bottomSheet.layoutParams = layoutParams
        behavior.state = BottomSheetBehavior.STATE_EXPANDED
        behavior.isDraggable = false / true
    }

}

Edited) The library was updated! you can use new library version

implementation 'com.google.android.material:material:1.4.0'

The examples are the same, good luck and good code

Mastery answered 8/4, 2020 at 4:47 Comment(2)
This seriously needs to be the default answer. I've wasted precious time to try all the solutions before this one, and none compares with it.Coates
I can't understand this answer. So , please explain in detail.Brochette
L
35

Alright, so the accepted answer didn't work for me. However, Виталий Обидейко's answer inspired my final solution.

First, I created the following custom BottomSheetBehavior. It overrides all of the methods involving touch, and returns false (or did nothing) if it is locked. Otherwise, it acts like a normal BottomSheetBehavior. This disables the user's ability to drag down, and does not affect changing the state in code.

LockableBottomSheetBehavior.java

public class LockableBottomSheetBehavior<V extends View> extends BottomSheetBehavior<V> {

    private boolean mLocked = false;

    public LockableBottomSheetBehavior() {}

    public LockableBottomSheetBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setLocked(boolean locked) {
        mLocked = locked;
    }

    @Override
    public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
        boolean handled = false;

        if (!mLocked) {
            handled = super.onInterceptTouchEvent(parent, child, event);
        }

        return handled;
    }

    @Override
    public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
        boolean handled = false;

        if (!mLocked) {
            handled = super.onTouchEvent(parent, child, event);
        }

        return handled;
    }

    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, V child, View directTargetChild, View target, int nestedScrollAxes) {
        boolean handled = false;

        if (!mLocked) {
            handled = super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
        }

        return handled;
    }

    @Override
    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx, int dy, int[] consumed) {
        if (!mLocked) {
            super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
        }
    }

    @Override
    public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target) {
        if (!mLocked) {
            super.onStopNestedScroll(coordinatorLayout, child, target);
        }
    }

    @Override
    public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, V child, View target, float velocityX, float velocityY) {
        boolean handled = false;

        if (!mLocked) {
            handled = super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY);
        }

        return handled;

    }
}

Here's an example of how to use it. In my case, I needed it so the Bottom Sheet locked when expanded.

activity_home.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <android.support.design.widget.CollapsingToolbarLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_scrollFlags="scroll|snap"
            app:titleEnabled="false"/>
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"/>
    </android.support.design.widget.AppBarLayout>

    <!-- Use layout_behavior to set your Behavior-->
    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutManager="android.support.v7.widget.LinearLayoutManager"
        app:layout_behavior="com.myapppackage.LockableBottomSheetBehavior"/>

</android.support.design.widget.CoordinatorLayout>

HomeActivity.java

public class HomeActivity extends AppCompatActivity {
    BottomSheetBehavior mBottomSheetBehavior;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);

        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
        recyclerView.setAdapter(new SomeAdapter());

        mBottomSheetBehavior = BottomSheetBehavior.from(recyclerView);
        mBottomSheetBehavior.setBottomSheetCallback(new MyBottomSheetCallback());
    }

    class MyBottomSheetCallback extends BottomSheetBehavior.BottomSheetCallback() {
        @Override
        public void onStateChanged(@NonNull View bottomSheet, int newState) {
            if (newState == BottomSheetBehavior.STATE_EXPANDED) {
                if (mBottomSheetBehavior instanceof LockableBottomSheetBehavior) {
                    ((LockableBottomSheetBehavior) mBottomSheetBehavior).setLocked(true);
                }
            }
        }

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

Hope this helps clear up a lot of the confusion!

Labors answered 25/11, 2016 at 5:22 Comment(7)
Nice, it's best answer that we can avoid workaround these states which lead to miss events. Thank you.Oliguria
@James - Nice answer but now I am not able to setPeekHeight(). Any idea?Copier
I tried this. it works for me. thanks bro for saving my assGangue
This is a good workaround, although it is not updated as of today. The OnNestedPreScroll and certain other methods have been deprecated. Need to update those methods and it works just fine.Epicureanism
Hello, it doesn't work on a BottomSheetDialogFragment, i can still drag the bottomsheetIsabellisabella
Works if you swap out the deprecated methods for the ones that include the extra type int parameterDowntoearth
I am getting below issue- Could not inflate Behavior subclass com.rp.th.sit.order.cart.presentation.view.cartutil.LockableBottomSheetBehavior why is it?Prehensible
S
23

I ended up writing a workaround to address this use case of dynamically disabling user dragging, whereby BottomSheetBehavior is subclassed to override onInterceptTouchEvent, and to ignore it when a custom flag (in this case mAllowUserDragging) is set to false:

import android.content.Context;
import android.support.design.widget.BottomSheetBehavior;
import android.support.design.widget.CoordinatorLayout;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class WABottomSheetBehavior<V extends View> extends BottomSheetBehavior<V> {
    private boolean mAllowUserDragging = true;
    /**
     * Default constructor for instantiating BottomSheetBehaviors.
     */
    public WABottomSheetBehavior() {
        super();
    }

    /**
     * Default constructor for inflating BottomSheetBehaviors from layout.
     *
     * @param context The {@link Context}.
     * @param attrs   The {@link AttributeSet}.
     */
    public WABottomSheetBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setAllowUserDragging(boolean allowUserDragging) {
        mAllowUserDragging = allowUserDragging;
    }

    @Override
    public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
        if (!mAllowUserDragging) {
            return false;
        }
        return super.onInterceptTouchEvent(parent, child, event);
    }
}

And in your layout xml:

    <FrameLayout
        android:id="@+id/bottom_sheet_frag_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:behavior_hideable="true"
        app:behavior_peekHeight="@dimen/bottom_sheet_peek_height"
        app:elevation="@dimen/bottom_sheet_elevation"
        app:layout_behavior="com.example.ray.WABottomSheetBehavior" />

So far, this is the most consistently behaving solution for disabling user dragging on the Bottom Sheet on demand.

All of the other solutions that relied on firing another setState call in the onStateChanged callback resulted in the BottomSheet getting into a bad state, or causes significant UX issues (in the case of posting the setState call in a Runnable).

Hope this helps someone :)

Ray

Sinless answered 21/4, 2016 at 16:48 Comment(11)
That's pretty neatBindweed
Good solution but it doesn't work when there is a listview in the bottom sheet.Barbabas
@BeeingJk Instead of the FrameLayout, use NestedScrollView, and set bottomSheetFragContainer.setNestedScrollingEnabled(false);Dubitation
How make it usable for MapView (to avoid zooming problems )Govea
@AfzalivE it will work for MapView in BootomSheetFragment?Govea
SOLVED: by setting callback CoordinatorLayout.Behavior behavior = layoutParams.getBehavior(); if (behavior != null && behavior instanceof BottomSheetBehavior) { ((BottomSheetBehavior) behavior).setBottomSheetCallback(mBottomSheetBehaviorCallback); }Govea
I use this apporach in order to manage simultanously 4 bottom sheet at once. The problem I have is when i disable onInterceptTouchEvent() in all MyBottomSheetBehaviour the last BottomSheet is still draggableLogician
This doesn't wok for me ! PS : I have a scrollable text in the bottomsheetKutenai
How do you cast it during initialisation? This gives me warning WABottomSheetBehavior<View> behaviour = (WABottomSheetBehavior) BottomSheetBehavior.from(sheetView);Ewell
Sometimes it stucks and stay locked even dragging is allowedNeeley
This doens't work. Follow the previous answer where it has been shown how to override other methods.Ssr
C
13

Late answer, but, this is what worked for me, which is a bit different to what others have suggested.

You could try setting the cancelable property to false, i.e.

setCancelable(false);

and then manually handling the events where you would like to dismiss the dialog in the setupDialog method.

@Override
public void setupDialog(final Dialog dialog, final int style) {

    // handle back button
    dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
        @Override
        public boolean onKey(final DialogInterface dialog, final int keyCode, final KeyEvent event) {
            if (keyCode == KeyEvent.KEYCODE_BACK) {
                dialog.dismiss();
            }
            return true;
        }
    });

    // handle touching outside of the dialog
    final View touchOutsideView = getDialog().getWindow().getDecorView().findViewById(android.support.design.R.id.touch_outside);
    touchOutsideView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(final View view) {
            dialog.dismiss();
        }
    });
}

This works with a ListView inside the dialog fragment, which was where I was getting a little stuck with other solutions.

Cosmo answered 22/3, 2017 at 23:2 Comment(2)
Nice concise solution. To anyone reading this, you'll (probably) want additional checks for event.isCanceled() and event.getAction() == MotionEvent.ACTION_UP before dismissing the dialog -- this will prevent mis-clicks from firing the dismissal.Broome
Thanks for this. This is the simplest solution to disable dragging.Laughlin
M
10

Expected behavior:

  • BottomSheet does not close on drag-down
  • BottomSheet closes if touched outside of the dialog window

Code:

class MyBottomSheet : BottomSheetDialogFragment () {

   override fun onActivityCreated(savedInstanceState: Bundle?) {
       super.onActivityCreated(savedInstanceState)
       disableBottomSheetDraggableBehavior()
   }

   private fun disableBottomSheetDraggableBehavior() {
      this.isCancelable = false
      this.dialog?.setCanceledOnTouchOutside(true)
   }

 }
Mcdaniel answered 15/10, 2019 at 4:34 Comment(1)
For some reason, I cant close the dialog touching outside, but it works to disable the dragFrigg
N
8

The accepted answer doesn't work on the first test device I use. And the bounce back is not smooth. It seems better to set the state to STATE_EXPANDED only after a user releases the dragging. The following is my version:

    final BottomSheetBehavior behavior = BottomSheetBehavior.from(findViewById(R.id.bottomSheet));
    behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
        @Override
        public void onStateChanged(@NonNull View bottomSheet, int newState) {
            if (newState > BottomSheetBehavior.STATE_DRAGGING)
                bottomSheet.post(new Runnable() {
                    @Override public void run() {
                        behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
                    }
                });
        }

        @Override
        public void onSlide(@NonNull View bottomSheet, float slideOffset) {
        }
    });
Nomanomad answered 5/3, 2016 at 2:33 Comment(1)
Let me tell you the problem with throwing it in a runnable unless that's what you want. You can't dismiss it with a button because, it needs to drag to dismiss. And, it'll always respond to dragging, just that it would prevent the user from dragging to dismissTemperance
C
7

Add this code to BottomSheetBehavior object. Dragging will be disabled. Works fine for me.

final BottomSheetBehavior behavior = BottomSheetBehavior.from((View) view.getParent());
    behavior.setHideable(false);
    behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {

      @Override
      public void onStateChanged(@NonNull View bottomSheet, int newState) {
        if (newState == BottomSheetBehavior.STATE_DRAGGING) {
          behavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
        }

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

      }
});
Cochabamba answered 10/2, 2017 at 23:9 Comment(1)
This does not disable swiping. It collapses the bottom sheet completely.Sinistrodextral
B
7

With 'com.google.android.material:material:1.2.0-alpha06'

Works great with NestedScrollView and RecyclerView

Example code:

    LinearLayout contentLayout = findViewById(R.id.contentLayout);
    sheetBehavior = BottomSheetBehavior.from(contentLayout);
    sheetBehavior.setDraggable(false);
Brunella answered 29/5, 2020 at 9:55 Comment(1)
sheetBehavior.setDraggable(false); this one line did the job inside onViewCreated method. Cheers!Rammer
R
6

To lock the BottomSheet and avoid the user to swipe it out this is what I did

public void showBottomSheet() {
    bsb.setHideable(false);
    bsb.setState(BottomSheetBehavior.STATE_EXPANDED);
}

public void hideBottomSheet() {
    bsb.setHideable(true);
    bsb.setState(BottomSheetBehavior.STATE_COLLAPSED);
}

It works quite well for me.

Ragi answered 24/8, 2016 at 2:11 Comment(2)
This solution was appealing but bizarrely causes the bottom sheet to appear from the top of the screen instead of the bottom! It disappears the normal way however. It's very Star Trek.Dosia
I needed to make a sight modification and instead use BottomSheetBehavior.STATE_HIDDEN. In such case, you must also not call setPeekHeight(). This is much less complicated than other solutions here.Neutrino
N
6

A sample with BottomSheetDialogFragment. It works perfectly.

Edit 09/04/2020: Replaced depreciated setBottomSheetCallback() with addBottomSheetCallback()

class FragMenuBDrawer : BottomSheetDialogFragment() {

    ...

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        val dialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog

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

            behavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
                override fun onStateChanged(bottomSheet: View, newState: Int) {
                    if (newState == BottomSheetBehavior.STATE_DRAGGING) {
                        behavior.state = BottomSheetBehavior.STATE_EXPANDED
                    }
                }

                override fun onSlide(bottomSheet: View, slideOffset: Float) {}
            })
        }

        // Do something with your dialog like setContentView() or whatever
        return dialog
    }

    ...
}
Nervy answered 14/8, 2019 at 11:20 Comment(0)
P
5

Easy way to lock dragging is setPeekHeight same as view height. For example:

private LinearLayout bottomSheet;
private BottomSheetBehavior bottomBehavior;

@Override
public void onResume() {
    super.onResume();
    bottomBehavior = BottomSheetBehavior.from((bottomSheet);
    bottomBehavior.setPeekHeight(bottomSheet.getHeight());
    bottomBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
}
Protease answered 28/3, 2017 at 3:46 Comment(0)
S
3

You don't need to block all events when the bottom sheet is disabled. You can block only ACTION_MOVE event. That's why use custom bottom sheet behavior like this

public class BottomSheetBehaviorWithDisabledState<V extends View> extends BottomSheetBehavior<V> {
    private boolean enable = true;

    /**
     * Default constructor for instantiating BottomSheetBehaviors.
     */
    public BottomSheetBehaviorWithDisabledState() {
        super();
    }

    /**
     * Default constructor for inflating BottomSheetBehaviors from layout.
     *
     * @param context The {@link Context}.
     * @param attrs   The {@link AttributeSet}.
     */
    public BottomSheetBehaviorWithDisabledState(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setEnable(boolean enable){
        this.enable = enable;
    }

    @Override
    public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
        if (!enable && event.getAction() == MotionEvent.ACTION_MOVE){
            return false;
        }
        return super.onInterceptTouchEvent(parent, child, event);
    }
}
Smallpox answered 3/3, 2017 at 14:41 Comment(1)
How do you use this class? I'm getting an IllegalArgumentException: The view is not associated with BottomSheetBehaviorStable
C
3

This is basically the kotlin version of the right answer at the top:

    class LockedBottomSheetBehavior<V : View>(context: Context, attrs: AttributeSet) :
        BottomSheetBehavior<V>(context, attrs) {

    companion object {
        fun <V : View> from(view: V): LockedBottomSheetBehavior<*> {
            val params = view.layoutParams as? CoordinatorLayout.LayoutParams
                    ?: throw IllegalArgumentException("The view is not a child of CoordinatorLayout")
            return params.behavior as? LockedBottomSheetBehavior<*>
                    ?: throw IllegalArgumentException(
                            "The view is not associated with BottomSheetBehavior")
        }
    }

    override fun onInterceptTouchEvent(
            parent: CoordinatorLayout,
            child: V, event: MotionEvent
    ) = false

    override fun onTouchEvent(
            parent: CoordinatorLayout,
            child: V,
            event: MotionEvent
    ) = false

    override fun onStartNestedScroll(
            coordinatorLayout: CoordinatorLayout,
            child: V,
            directTargetChild: View,
            target: View,
            axes: Int,
            type: Int) = false

    override fun onNestedPreScroll(
            coordinatorLayout: CoordinatorLayout,
            child: V,
            target: View,
            dx: Int,
            dy: Int,
            consumed: IntArray,
            type: Int) {
    }

    override fun onStopNestedScroll(
            coordinatorLayout: CoordinatorLayout,
            child: V,
            target: View,
            type: Int) {
    }

    override fun onNestedPreFling(
            coordinatorLayout: CoordinatorLayout,
            child: V,
            target: View,
            velocityX: Float,
            velocityY: Float
    ) = false
}
Competitive answered 22/3, 2018 at 14:10 Comment(2)
How do you use this class? I'm getting an IllegalArgumentException: The view is not associated with BottomSheetBehaviorStable
app:layout_behavior="UserLockBottomSheetBehavior"> in xml and then in code you do the following. // get the bottom sheet view LinearLayout llBottomSheet = (LinearLayout) findViewById(R.id.bottom_sheet); // init the bottom sheet behavior BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(llBottomSheet);Competitive
E
3

Here is a working version of the top solution in Kotlin:

import android.support.design.widget.BottomSheetBehavior
import android.support.design.widget.CoordinatorLayout
import android.view.MotionEvent
import android.view.View

class CustomBottomSheetBehavior<V : View> : BottomSheetBehavior<V>() {

    @Suppress("UNCHECKED_CAST")
    companion object {
        fun <V : View> from(view: V): CustomBottomSheetBehavior<V> {
            val params = view.layoutParams as? CoordinatorLayout.LayoutParams ?:
                throw IllegalArgumentException("The view is not a child of CoordinatorLayout")
                params.behavior as? BottomSheetBehavior<V> ?:
                    throw IllegalArgumentException("The view is not associated with BottomSheetBehavior")
                params.behavior = CustomBottomSheetBehavior<V>()
            return params.behavior as CustomBottomSheetBehavior<V>
        }
    }

    override fun onInterceptTouchEvent(parent: CoordinatorLayout, child: V, event: MotionEvent): Boolean {
        return false
    }

    override fun onTouchEvent(parent: CoordinatorLayout, child: V, event: MotionEvent): Boolean {
        return false
    }

    override fun onStartNestedScroll(coordinatorLayout: CoordinatorLayout, child: V, directTargetChild: View, target: View, axes: Int, type: Int): Boolean {
        return false
    }

    override fun onNestedPreScroll(coordinatorLayout: CoordinatorLayout, child: V, target: View, dx: Int, dy: Int, consumed: IntArray, type: Int) {}

    override fun onStopNestedScroll(coordinatorLayout: CoordinatorLayout, child: V, target: View, type: Int) {}

    override fun onNestedPreFling(coordinatorLayout: CoordinatorLayout, child: V, target: View, velocityX: Float, velocityY: Float): Boolean {
        return false
    }
}

Then whenever you wanna use:

val bottomSheetBehavior by lazy {
    CustomBottomSheetBehavior.from(bottom_sheet_main)
}

The bottom_sheet_main is the actual view using Kotlin Android Extensions.

Emotion answered 2/5, 2018 at 11:17 Comment(0)
B
3

set bottomSheet onClickListener to null.

bottomSheet.setOnClickListener(null);

this line disables all action about bottomSheet only and does not effect on inner view.

Baculiform answered 5/8, 2018 at 4:43 Comment(1)
This causes unexpected animation when the Bottom Sheet is attempting to close.Sinistrodextral
V
3

Try this.

1) Create bottom sheet and declare the variable in your java class like

private BottomSheetBehavior sheetBehavior;

2) sheetBehavior = BottomSheetBehavior.from(bottomSheet);

3) In the bottom sheet callback function add the following lines.

sheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
            @Override
            public void onStateChanged(@NonNull View bottomSheet, int newState) {
                switch (newState) {
                    case BottomSheetBehavior.STATE_HIDDEN:
                        Log.d(TAG, "--------------  STATE_HIDDEN");
                        break;
                    case BottomSheetBehavior.STATE_EXPANDED: {
                        Log.d(TAG, "--------------  STATE_EXPANDED");
                    }
                    break;
                    case BottomSheetBehavior.STATE_COLLAPSED: {
                        Log.d(TAG, "--------------  STATE_COLLAPSED");
                    }
                    break;
                    case BottomSheetBehavior.STATE_DRAGGING:
                        sheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
                        break;
                    case BottomSheetBehavior.STATE_SETTLING:
                        Log.d(TAG, "--------------  STATE_SETTLING");
                        break;
                }
            }

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

            }
        });
Vachell answered 14/5, 2019 at 6:36 Comment(1)
Thank you! This worked for me. Just one comment: should be used sheetBehavior.addBottomSheetCallback instead of setBottomSheetCallback, which is deprecated.Pumphrey
P
3

Call this method in your onCreateView function to make the bottomsheet non-dismissable, non-cancellable, and non-draggable (use whatever applies to your use case):

    private fun disableDialog() {
        this.dialog?.let { bottomSheet ->
            // Disable dismiss on outside touch
            bottomSheet.setCanceledOnTouchOutside(false)

            // Hide the cancel button
            bottomSheet.setCancelable(false)

            // Disable back key press
            bottomSheet.setOnKeyListener { _, keyCode, _ ->
                keyCode == KeyEvent.KEYCODE_BACK
            }

            // Make it non-draggable
            bottomSheet.setOnShowListener {
                (it as BottomSheetDialog).behavior.setDraggable(false)
            }
        }
    }
Pinnacle answered 15/10, 2021 at 19:40 Comment(0)
W
3

For Dialogs extended with BottomSheetDialogFragment(), simply use these

To Disable Swipe Feature

if (dialog?.window != null) {
   dialog!!.setCancelable(false)
}

To Enable Swipe Feature

if (dialog?.window != null) {
   dialog!!.setCancelable(true)
}
Who answered 26/10, 2021 at 11:44 Comment(0)
D
3

val behavior = BottomSheetBehavior.from(bottomSheet)
behaviour.isDraggable = false
Demetriusdemeyer answered 15/12, 2021 at 11:5 Comment(0)
K
3

When you have a class extending BottomSheetDialogFragment

One common miss I see in most of the answers is you should not create local variable of BottomSheetBehavior, updating fields on local variable won't reflect on the actual dialog behavior. So IMO, following code won't work

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    val dialog = super.onCreateDialog(savedInstanceState)
    dialog.setOnShowListener {
        val bottomSheet = it.findViewById<View>(
                com.google.android.material.R.id.design_bottom_sheet
            ) as FrameLayout
        val behavior = BottomSheetBehavior.from(bottomSheet)
        behavior.isDraggable = false
    }
    return dialog
}

But this should work

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    val dialog = super.onCreateDialog(savedInstanceState)
    dialog.setOnShowListener {
        it as BottomSheetDialog
        it.behavior.isDraggable = false
    }
    return dialog
}
Kilian answered 13/12, 2022 at 6:4 Comment(1)
The reason your first code block is not working, is due to the instantiated bottomSheet not being added to the dialog. Try adding dialog.setContentView(bottomSheet) and change val behavior = BottomSheetBehavior.from(bottomSheet) to val behavior = BottomSheetBehavior.from<View>(bottomSheet.parent as View) ; then the changes will reflect.Leucas
P
2

I have found amazing solution. The initial problem was once bottomSheet was going to HIDDEN state then it was not showing up at bottomSheetDialog.show(). But I wanted to get the dialog visible on show() method and also wanted to enable the user to swipe it down so that it feels like bottom sheet. Below is what I did..

    BottomSheetDialog itemTypeDialog = new BottomSheetDialog(this);
    View bottomSheetView = getLayoutInflater().inflate(R.layout.dialog_bottomsheet, null);
    itemTypeDialog.setContentView(bottomSheetView);
    BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from((View) bottomSheetView.getParent());
    bottomSheetBehavior.setBottomSheetCallback(bottomSheetCallback); // You can also attach the listener here itself.

    BottomSheetBehavior.BottomSheetCallback bottomSheetCallback =  new BottomSheetBehavior.BottomSheetCallback() {
    @Override
    public void onStateChanged(@NonNull View bottomSheet, int newState) {
        Log.d(TAG, "BottomSheetCallback: " + newState);
        if (newState == BottomSheetBehavior.STATE_HIDDEN) {
            bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
            itemTypeDialog.dismiss();
        } 
    }

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

    }
};
Pentstemon answered 14/1, 2017 at 7:59 Comment(1)
this one is a perfect answerCerenkov
M
2
  1. Copy BottomSheetDialog to your project and rename to MyBottomSheetDialog
  2. add getBottomSheetBehavior to MyBottomSheetDialog
  3. use MyBottomSheetDialog instead BottomSheetDialog
  4. bottomSheetBehavior.setBottomSheetCallback

code like this

public class MyBottomSheetDialog extends AppCompatDialog {

    // some code

    public BottomSheetBehavior<FrameLayout> getBottomSheetBehavior() {
        return mBehavior;
    }

    // more code

in your code

    final BottomSheetBehavior<FrameLayout> bottomSheetBehavior = myBottomSheetDialog.getBottomSheetBehavior();
    bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
        @Override
        public void onStateChanged(@NonNull View bottomSheet, int newState) {
            if (newState == BottomSheetBehavior.STATE_DRAGGING) {
                bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
            }
        }

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

        }
Mut answered 22/12, 2017 at 12:41 Comment(0)
N
2

To prevent user from dragging the bottom sheet to dismiss/open

    bottomSheetDialog_OverView = new BottomSheetDialog(context);
    View dialogView = View.inflate(context, R.layout.dialog_overview, null);
    bottomSheetDialog_OverView.getBehavior().setDraggable(false);
Nathanson answered 21/10, 2021 at 9:32 Comment(0)
L
2

The fastest solution is only write this. bottomSheet.getBehavior().setDraggable(false);

Lingonberry answered 19/5, 2023 at 2:12 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Belong
P
1

I have the same issue in BottomSheetDialogFragment and apply many solutions using the behavior of dialog but none of those solve my issue and then I solved it but setting setCancelable(false); at the time of initialization of dialog.

DialogEndRide dialogCompleteRide = new DialogEndRide();
dialogCompleteRide.setCancelable(false);
dialogCompleteRide.show(getChildFragmentManager(), "");

This will disable gesture on BottomSheetDialogFragment and you can dismiss dialog programmatically by using dismiss(); function.

Pontianak answered 10/7, 2019 at 9:32 Comment(0)
E
1

At first, I just wanna give thanks to all of you who tried to give an answer. I am just writing this answer by solving this problem as I want. I'm going to describe how I do that step by step by taking help from here.

Visualization: After clicking on the Button Show BottomSheet you will see the second screen. Now you will see that BottomSheet is just locked up for dragging. But if you click on the Country List the BottomSheet will hide. This was the description now let's dig into the Code.

  • At first, add the design support library to your build.gradle file:

    implementation 'com.android.support:design:28.0.0'

  • UserLockBottomSheetBehavior.java: Credit: James Davis (Thanks Man)

public class UserLockBottomSheetBehavior<V extends View> extends BottomSheetBehavior<V> {

    public UserLockBottomSheetBehavior() {
        super();
    }

    public UserLockBottomSheetBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
        return false;
    }

    @Override
    public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
        return false;
    }

    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, V child, View directTargetChild, View target, int nestedScrollAxes) {
        return false;
    }

    @Override
    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx, int dy, int[] consumed) {
    }

    @Override
    public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target) {
    }

    @Override
    public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, V child, View target, float velocityX, float velocityY) {
        return false;
    }

}
  • bottomsheet.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/bottomSheet"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center_vertical"
    android:orientation="vertical"
    app:behavior_hideable="true"
    app:layout_behavior="com.samsolution.custombottomsheet.UserLockBottomSheetBehavior">

 <RelativeLayout
     android:id="@+id/minimizeLayout"
     android:background="@color/colorPrimary"
     android:layout_width="match_parent"
     android:layout_height="?android:attr/actionBarSize">

     <TextView
         android:layout_centerHorizontal="true"
         android:padding="16dp"
         android:layout_width="wrap_content"
         android:layout_height="?android:attr/actionBarSize"
         android:gravity="center_horizontal|center"
         android:text="Country List"
         android:textColor="#FFFFFF"
         android:textStyle="bold" />
 </RelativeLayout>

    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <ListView
            android:id="@+id/homeCountryList"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </android.support.v7.widget.CardView>

</LinearLayout>
  • activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FFFFFF"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_gravity="center"
        android:onClick="showCountryListFromBottomSheet">

        <Button
            android:layout_gravity="center"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@android:color/holo_red_light"
            android:onClick="showCountryListFromBottomSheet"
            android:padding="16dp"
            android:text="Show BottomSheet"
            android:textAllCaps="false"
            android:textColor="#ffffff" />

    </LinearLayout>

    <include layout="@layout/bootomsheet" />

</android.support.design.widget.CoordinatorLayout>
  • MainActivity.java
public class MainActivity extends AppCompatActivity {

    private BottomSheetBehavior<LinearLayout> bottomSheetBehavior;                                  // BottomSheet Instance
    LinearLayout bottomsheetlayout;
    String[] list = {"A", "B", "C", "D", "A", "B", "C", "D","A", "B", "C", "D","A", "B", "C", "D","A", "B", "C", "D"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        bottomsheetlayout = findViewById(R.id.bottomSheet);
        bottomSheetBehavior = BottomSheetBehavior.from(bottomsheetlayout);

        ListView listView = findViewById(R.id.homeCountryList);
        ArrayAdapter<String> adapter = new ArrayAdapter<>(this,android.R.layout.simple_list_item_1,list);
        listView.setAdapter(adapter);

        bottomSheetHide();                                                                          //BottomSheet get hide first time

        RelativeLayout minimizeLayoutIV;                                                            // It will hide the bottomSheet Layout
        minimizeLayoutIV = findViewById(R.id.minimizeLayout);
        minimizeLayoutIV.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
               bottomSheetHide();
            }
        });
    }

    public void showCountryListFromBottomSheet(View view) {
        bottomSheetBehavior.setHideable(false);
        bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
    }

    public void bottomSheetHide(){
        bottomSheetBehavior.setHideable(true);
        bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
    }
}

First Screen Second Screen

Erik answered 15/7, 2019 at 10:57 Comment(0)
P
1

this is the first result in google so I believe its only fair to put the simple solution in here:

   private fun disableDragToDismiss() {
    if (dialog is BottomSheetDialog) {
        val bsDialog = dialog as BottomSheetDialog
        bsDialog.behavior.isHideable = false
    } else {
        Log.d(TAG, " BottomSheetDialog with dialog that is not BottomSheetDialog")
    }
}

and than just call it from onCreateView() in the BottomSheetDialogFragment implementation

Psychotomimetic answered 24/2, 2020 at 10:41 Comment(0)
P
1

The solution from accepted answer did mostly worked for me, but with one issue: views, which are behind the bottom sheet view, started to react on touch events, if touch event is happening on bottom sheet's area, which is free of child views. In other words, as you may see in image below, when user slides finger inside bottom sheet, then map starts to react on it.

bottom sheet touch area

To fix the issue, I've modified onInterceptTouchEvent method by setting touchListener on bottom sheet view (rest of code remains the same as in accepted solution).

override fun onInterceptTouchEvent(
        parent: CoordinatorLayout,
        child: V, event: MotionEvent
    ): Boolean {
        child.setOnTouchListener { v, event ->
            true
        }
        return false
    }
Pointsman answered 10/3, 2020 at 11:8 Comment(0)
B
1

FYI: Following Material UI best practices, you have to create you own class, extending BottomSheetDialogFragment. Inside this class you can override onStart method and add this code in it:

dialog?.let {
            val bottomSheet = it.findViewById<View>(
                com.google.android.material.R.id.design_bottom_sheet
            ) as FrameLayout
            val behavior = BottomSheetBehavior.from(bottomSheet)

            behavior.state = BottomSheetBehavior.STATE_EXPANDED
            behavior.isDraggable = false
        }

Worked perfectly for me

Bytom answered 14/9, 2021 at 20:13 Comment(0)
M
0

Adjusting the peakHeight value worked for me.

I set the peakheight as the height of bottomsheet if it is expanded.

    private val bottomSheetCallback = object : BottomSheetBehavior.BottomSheetCallback() {
    override fun onSlide(bottomSheet: View, slideOffset: Float) {

    }

    override fun onStateChanged(bottomSheet: View, newState: Int) {
        if (newState == BottomSheetBehavior.STATE_EXPANDED)
            bottomSheetBehavior.peekHeight = bottomSheet.height
    }
}
Maimonides answered 25/9, 2018 at 10:55 Comment(3)
This is not ideal as it may cause unexpected animations.Sinistrodextral
In my case. It didn't caused any animations issue at all. It just don't move after card is expanded. It's not ideal but it did work as expected!Maimonides
Interesting, that could be the case. I resolved the issue with my Bottom Sheet closing unexpectedly by setting the CollapsingToolbarLayout's Toolbar to Invisible or Gone when the Bottom Sheet is open. A touch interaction related to the Toolbar even though it was underneath was causing the Bottom Sheet to close unexpectedly. The issue is fixed now.Sinistrodextral
S
0
    LayoutInflater inflater = LayoutInflater.from(context);
            View view = inflater.inflate(R.layout.bottomsheet_view_profile_image, null);
            BottomSheetDialog dialog = new BottomSheetDialog(context);
            dialog.setContentView(view);
            dialog.setCancelable(false);


            BottomSheetBehavior behavior = BottomSheetBehavior
                    .from(((View) view.getParent()));
            behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
                @Override
                public void onStateChanged(@NonNull View bottomSheet, int newState) {
                    if (newState == BottomSheetBehavior.STATE_DRAGGING) {
                        behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
                    }
                }

                @Override
                public void onSlide(@NonNull View bottomSheet, float slideOffset) {
                }
            });
            behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
            behavior.setSkipCollapsed(true);
            dialog.show();
Stealth answered 7/6, 2019 at 11:17 Comment(0)
A
0

You can use android.app.Dialog with Gravity.BOTTOM of Window instead:

Dialog dialog = new Dialog(this);
dialog.getWindow().getAttributes().gravity = Gravity.BOTTOM;
dialog.show();

and if you want animation like in BottomSheetDialog add this to your styles.xml

<style name="BottomSheetDialog" parent="Theme.Design.Light.BottomSheetDialog">
    <item name="bottomSheetStyle">@style/bottomSheetStyleWrapper</item>
</style>

<style name="bottomSheetStyleWrapper" parent="Widget.Design.BottomSheet.Modal">
    <item name="android:background">@android:color/transparent</item>
</style>

and in Java code:

Dialog dialog = new Dialog(this, R.style.BottomSheetDialog);
Abc answered 14/2, 2021 at 14:4 Comment(0)
W
0
private fun bottomSheetBehaviour(bottomSheet: BottomSheetDialog) {
    bottomSheet.setOnShowListener {

        val bottomSheetDialog = it as BottomSheetDialog
        val parentLayout =
            bottomSheetDialog.findViewById<View>(com.google.android.material.R.id.design_bottom_sheet)
        parentLayout?.let { parentView ->
            val behaviour = BottomSheetBehavior.from(parentView)
            setupFullHeight(parentView)
            behaviour.isDraggable = false
            behaviour.peekHeight = parentView.height
            behaviour.state = BottomSheetBehavior.STATE_EXPANDED
        }
        bottomSheet.setCancelable(false)
    }
}
  • behaviour.peekHeight = parentView.height
  • bottomSheet.setCancelable(false)

The above 2 line help me to fix the behaviour for BottomSheetDialogFragment

Waldner answered 21/9, 2022 at 13:22 Comment(0)
D
-1
BottomSheetDialog calcDialog = new BottomSheetDialog(this);
View view = getLayoutInflater().inflate(R.layout.bottom_sheet_calc, null);
calcDialog.setContentView(view);
calcDialog.setCancelable(false);
Dyslogistic answered 14/11, 2020 at 7:50 Comment(2)
The question is very detailed with plenty of relevant code to explain the problem, but it's hard to see the connection between your answer and the question because you haven't added any explanation to your code sample.Skilled
@Skilled sorry for no explanation I added.. but as in the question user wanted to disable bottom sheet dragging property so I suggested to use setCancelable(false); method of bottom sheetDyslogistic
U
-2

Simply use : bottomSheet.dismissOnDraggingDownSheet = false

Copied from Material.io website :

let viewController: ViewController = ViewController() let bottomSheet: MDCBottomSheetController = MDCBottomSheetController(contentViewController: viewController)

// **** This line prevents dismiss by dragging bottomSheet ****

bottomSheet.dismissOnDraggingDownSheet = false

present(bottomSheet, animated: true, completion: nil)

Uninterested answered 3/4, 2020 at 5:16 Comment(1)
it's for iOS here not AndroidErskine

© 2022 - 2024 — McMap. All rights reserved.