I have implemented bottomsheet behavior with NestedScrollView. And was wondering if it is possible to hide the bottomsheet view when touched outside.
-
2Is it a Self answered question? Because you have added question and answer same time, so I was asking. – Pankaj Kumar Jul 04 '16 at 13:27
-
6Yup so that others don't feel frustrated if having same problem. – Pradeep Kumar Kushwaha Jul 04 '16 at 13:30
-
For `BottomSheetDialogFragment` see https://stackoverflow.com/questions/40616833/bottomsheetdialogfragment-listen-to-dismissed-by-user-event. – CoolMind Apr 17 '19 at 08:42
10 Answers
Finally I was able to do this,
Used the following lines of code:
@Override public boolean dispatchTouchEvent(MotionEvent event){
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (mBottomSheetBehavior.getState()==BottomSheetBehavior.STATE_EXPANDED) {
Rect outRect = new Rect();
bottomSheet.getGlobalVisibleRect(outRect);
if(!outRect.contains((int)event.getRawX(), (int)event.getRawY()))
mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
}
}
return super.dispatchTouchEvent(event);
}
Hope it save someone's whole day!

- 2,231
- 3
- 23
- 34
-
1
-
9
-
1@RajeshNasit Implement the DispatchTouchEvent method in your activity and use the FragmentManager to call the Method in your Fragment. – Luca Ziegler Jan 13 '18 at 16:14
-
I done this but problem is that touch event called on click of swipe of each view. I want it for only specific views swipe – Rajesh N Jan 13 '18 at 16:16
-
-
1It works but is that a good solution ? Because each time we touch or scroll the screen, that method `dispatchTouchEvent` is called serveral times wich may be bad for battery usage and application performance. – ankalagba Jun 05 '21 at 20:40
Thanks the OP for the question/answer. I've used his code but improved on its cleanliness and wanted to share. Instead of extending a View and adding the interface, you can code that directly in the BottomSheetBehavior. Like this:
AutoCloseBottomSheetBehavior.java
import android.content.Context;
import android.graphics.Rect;
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 AutoCloseBottomSheetBehavior<V extends View> extends BottomSheetBehavior<V> {
public AutoCloseBottomSheetBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN &&
getState() == BottomSheetBehavior.STATE_EXPANDED) {
Rect outRect = new Rect();
child.getGlobalVisibleRect(outRect);
if (!outRect.contains((int) event.getRawX(), (int) event.getRawY())) {
setState(BottomSheetBehavior.STATE_COLLAPSED);
}
}
return super.onInterceptTouchEvent(parent, child, event);
}
}
and then you simply add it to your XML layout:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
... your normal content here ...
<SomeLayout... />
... the bottom sheet with the behavior
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_behavior="<com.package.name.of.the.class>.AutoCloseBottomSheetBehavior">
... the bottom sheet views
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>

- 39,391
- 16
- 102
- 144
-
7This works great! Small piece of advice... adding 'return true' after the call to 'setState' will stop clicks from passing through. In my use case, if clicking outside the dialog, I just wanted it to collapse without passing the click event to view behind it :) – Psest328 Apr 10 '19 at 16:27
-
1@Psest328 adding `return true` caused this to stop working for me *sometimes*. If I had the `return true` in there the sheet would only occasionally close. – Emil S. Nov 19 '20 at 21:46
-
For Activity:
@Override
public boolean dispatchTouchEvent(MotionEvent event){
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (mBottomSheetBehavior.getState()==BottomSheetBehavior.STATE_EXPANDED) {
Rect outRect = new Rect();
bottomSheet.getGlobalVisibleRect(outRect);
if(!outRect.contains((int)event.getRawX(), (int)event.getRawY()))
mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
}
}
return super.dispatchTouchEvent(event);
}
For Fragment: Use same method in Activity like,
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (fragment != null && fragment instanceof HomeFragment) {
((HomeFragment) fragment).hideBottomSheetFromOutSide(event);
}
}
return super.dispatchTouchEvent(event);
}
and Create Method in Fragment like:
/**
* Calling from Dashboard Activity
*
* @param event Motion Event
*/
public void hideBottomSheetFromOutSide(MotionEvent event) {
if (isBottomSheetMenuExpanded()) {
Rect outRect = new Rect();
mBinding.homeBottomSheetLayout.getGlobalVisibleRect(outRect);
if (!outRect.contains((int) event.getRawX(), (int) event.getRawY()))
mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
}
}
Hope it will helps you.
Thank you.

- 60,504
- 58
- 273
- 437
-
-
-
-
It works but is that a good solution ? Because each time we touch or scroll the screen, that method `dispatchTouchEvent` is called serveral times wich may be bad for battery usage and application performance. – ankalagba Jun 05 '21 at 20:42
-
Yeah, that's right. Do let me know if you find any other good solution. – Pratik Butani Jun 07 '21 at 04:43
Set a on click listener for your main layout (Coordinate layout in this case)
@OnClick(R.id.coordinateLayout)
public void onClickView(View view) {
if (sheetBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED) {
sheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
}
}
Note : Butterknife is used for on click otherwise use the code below in onCreate of the activity.
CoordinateLayout layout = (CoordinateLayout) findViewById(R.id. coordinateLayout);
layout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (sheetBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED) {
sheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
}
}
});

- 1,341
- 1
- 15
- 33

- 507
- 4
- 18
You can call the following code to close bottom sheet dialog on clicking outside.
BottomSheetDialog dialog = new BottomSheetDialog(context);
dialog.setContentView(R.layout.bottom_sheet);
dialog.setCanceledOnTouchOutside(true);
dialog.show();

- 2,028
- 1
- 18
- 30
someViewToClickOn.setOnClickListener(v ->
behavior.setState(BottomSheetBehavior.STATE_HIDDEN));
This works too! I first used BottomSheetBehavior.STATE_COLLAPSED
which doesn't work

- 7,010
- 4
- 54
- 68
There are many peoples finding a way to implement dispatchTouchEvent on fragment. So here's how they can do this:
create a custom layout as defined:
public class DispatchTouchEvent extends LinearLayout {
public interface onDispatchEvent
{
void dispatchEvent(MotionEvent e);
}
private onDispatchEvent dispatchEvent;
public DispatchTouchEvent(Context context) {
super(context);
}
public DispatchTouchEvent(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DispatchTouchEvent(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setDispatchEvent(onDispatchEvent dispatchEvent)
{
this.dispatchEvent=dispatchEvent;
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if(dispatchEvent!=null)
{
dispatchEvent.dispatchEvent(ev);
}
return super.dispatchTouchEvent(ev);
}
}
Now use this layout as the base of your fragment layout. Inside fragment initialise this layout as:
public class ABC extends fragment implements DispatchTouchEvent.onDispatchEvent
{
DispatchTouchEvent dispatchTouchEvent;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
....
dispatchTouchEvent = (DispatchTouchEvent)rootView.findViewById(R.id.dispatch_event);
dispatchTouchEvent.setDispatchEvent(this);
....
}
@Override
public void dispatchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (mBottomSheetBehavior.getState()==BottomSheetBehavior.STATE_EXPANDED)
{
Rect outRect = new Rect();
bottomSheet.getGlobalVisibleRect(outRect);
if(!outRect.contains((int)event.getRawX(), (int)event.getRawY()))
mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
}
}
}
}

- 2,231
- 3
- 23
- 34
I found UX issues with using the OP's answer or the AutoCloseBottomSheetBehavior.java version (from Budius). I changed the AutoCloseBottomSheetBehavior code in a way which seems cleaner to me and doesn't cause any UX issues (code is in Kotlin):
class AutoCloseBottomSheetBehavior<V : View>(
context: Context,
attrs: AttributeSet
) : BottomSheetBehavior<V>(context, attrs) {
private val gestureDetector: GestureDetectorCompat =
GestureDetectorCompat(context, object : GestureDetector.SimpleOnGestureListener() {
override fun onDown(event: MotionEvent?): Boolean {
return true
}
override fun onSingleTapUp(e: MotionEvent?): Boolean =
when {
state == STATE_EXPANDED -> {
state = STATE_COLLAPSED
true
}
state == STATE_COLLAPSED && isHideable -> {
state = STATE_HIDDEN
true
}
else -> false
}
})
@SuppressLint("ClickableViewAccessibility")
override fun onLayoutChild(parent: CoordinatorLayout, child: V, layoutDirection: Int): Boolean {
parent.setOnTouchListener { _, event ->
gestureDetector.onTouchEvent(event)
}
return super.onLayoutChild(parent, child, layoutDirection)
}
}
This collapses/hides the bottom sheet whenever the user performs a single tap on the parent CoordinatorLayout and also handles the case in which the bottom sheet is hidable (and we want to hide it if it's in a COLLAPSED state).

- 30,962
- 25
- 85
- 135

- 21
- 4
for me it was a simple setCancelable(true);
i.e
@Override
public void setupDialog(Dialog dialog, int style) {
super.setupDialog(dialog, style);
View contentView = View.inflate(getContext(), R.layout.layout_additional_prices, null);
unbinder = ButterKnife.bind(this, contentView);
dialog.setContentView(contentView);
dialog.setOnKeyListener(new BottomSheetBackDismissListener());
//makeBottomSheetFullScreen(getActivity(), mBottomSheetBehaviorCallback, contentView);
setCancelable(true);
}

- 3,382
- 28
- 31
There is two methods to make dialog is Cancelable :
Sets whether this dialog is cancelable with the BACK key.
Java
dialog.setCancelable(true);
Kotlin
dialog.setCancelable(true)
Sets whether this dialog is canceled when touched outside the window's bounds.
Java
dialog.setCanceledOnTouchOutside(true);
Kotlin
dialog.setCanceledOnTouchOutside(true)

- 692
- 10
- 15