I know BottomSheetDialog
does so already, but I need to use the regular BottomSheet
and behavior generated from BottomSheetBehavior.from()
. This BottomSheet
doesn't dim the background and also touch outside would not close it. Is there a way to dim the background when BottomSheet
is displayed? and maybe dismiss when touch outside. Basically the behavior just like BottomSheetDialog
but I must use BottomSheet
BottomSheetBehavior
directly.

- 8,084
- 8
- 48
- 62

- 3,505
- 6
- 33
- 71
-
Why must you use `BottomSheetBehavior`? – ianhanniballake Dec 01 '16 at 00:40
-
3Had the same problem. For me the reason to use `BottomSheet` and `BottomSheetBehavior` instead of `BottomSheetDialog(Fragment)` is that the `BottomSheet` plays nice when showing the keyboard. Using `BottomSheetDialogFragment` causes some janky animation. When showing the keyboard the DialogFragment just "snapps" to it's new position. BottomSheet animates smoothly up/down. – tir38 Jan 05 '17 at 16:46
-
1This has background dimming without fragment http://www.hidroh.com/2016/06/17/bottom-sheet-everything/ – Samuel Sep 29 '17 at 09:10
6 Answers
You can use this code 1. MainActivity.xml
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingTop="24dp">
<Button
android:id="@+id/button_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button 1"
android:padding="16dp"
android:layout_margin="8dp"
android:textColor="@android:color/white"
android:background="@android:color/holo_green_dark"/>
</LinearLayout>
</ScrollView>
<View
android:visibility="gone"
android:id="@+id/bg"
android:background="#99000000"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<android.support.v4.widget.NestedScrollView
android:id="@+id/bottom_sheet"
android:layout_width="match_parent"
android:layout_height="350dp"
android:clipToPadding="true"
android:background="@android:color/holo_orange_light"
app:layout_behavior="android.support.design.widget.BottomSheetBehavior"
>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="aefwea"
android:padding="16dp"
android:textSize="16sp"/>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
MAinActivity.java
public class MainActivity extends AppCompatActivity implements View.OnClickListener { private static final String TAG = "MainActivity"; private BottomSheetBehavior mBottomSheetBehavior; View bottomSheet; View mViewBg; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bottomSheet = findViewById(R.id.bottom_sheet); mViewBg = findViewById(R.id.mViewBg); Button button1 = (Button) findViewById(R.id.button_1); button1.setOnClickListener(this); mViewBg.setOnClickListener(this); mBottomSheetBehavior = BottomSheetBehavior.from(bottomSheet); mBottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { @Override public void onStateChanged(@NonNull View bottomSheet, int newState) { if (newState == BottomSheetBehavior.STATE_COLLAPSED) mViewBg.setVisibility(View.GONE); } @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { Log.d(TAG, "onSlide: slideOffset" + slideOffset + ""); mViewBg.setVisibility(View.VISIBLE); mViewBg.setAlpha(slideOffset); } }); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.button_1: { mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); break; } case R.id.bg: { mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); break; } } } @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 true; } } } return super.dispatchTouchEvent(event); } }

- 786
- 6
- 18
-
3I had to use `setPeekHeight(int peekHeight)` just as [this answer shows](https://stackoverflow.com/a/39062055/370798) in order to make this example work – Sam Sep 11 '17 at 17:37
-
1This works well! But isn't it bad for performance to repeatedly use findview? Especially in onSlide. Why not just obtain the reference to the view in oncreate? – behelit Nov 27 '18 at 23:18
-
-
-
Just use `addBottomSheetCallback` as `setBottomSheetCallback` is deprecated – Zain Aug 14 '21 at 03:55
You can create a custom fragment that has layout (kind of bottomSheet) attached to bottom and make the background transparent_black
& when touching on that BG remove that fragment. Ex :
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ff2020"
android:orientation="vertical"
tools:context="com.example.jiffysoftwaresolutions.copypastesampleapp.MainActivity">
<Button
android:id="@+id/show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Show" />
<FrameLayout
android:id="@+id/bottom_sheet_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"></FrameLayout>
</RelativeLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
private BottomSheetFragment bottomSheetFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.show).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (bottomSheetFragment == null) {
bottomSheetFragment = new BottomSheetFragment();
}
getSupportFragmentManager().beginTransaction().add(R.id.bottom_sheet_fragment_container, bottomSheetFragment).addToBackStack(null).commit();
}
});
}
public void removeBottomSheet() {
try {
getSupportFragmentManager().beginTransaction().remove(bottomSheetFragment).addToBackStack(null).commit();
} catch (Exception e) {
}
}
}
BottomSheetFragment.java
public class BottomSheetFragment extends Fragment {
private View rootView;
private LayoutInflater layoutInflater;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
layoutInflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.bottom_sheet_layout, container, false);
rootView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// remove sheet on BG touch
((MainActivity) getActivity()).removeBottomSheet();
}
});
return rootView;
}
}
bottom_sheet_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#6d000000"
android:gravity="bottom">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#fff"
android:orientation="vertical"
android:padding="5dp">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button1"
android:textColor="#000" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button2"
android:textColor="#000" />
</LinearLayout>
</RelativeLayout>
To Add that fragment with bottom_top/animation.. you can follow this link : Android Fragments and animation
Using the Interface - onSlide which as a parameter slideOffSet of type float , can be used to dim the background. The new offset of this bottom sheet within [-1,1] range. Offset increases as this bottom sheet is moving upward. From 0 to 1 the sheet is between collapsed and expanded states and from -1 to 0 it is between hidden and collapsed states.
if ( slideOffSet>=0 && slideOffSet<=1 ) {
mainActivityLayoutView.setAlpha( 1f - slideOffSet );
}
where mainActivityLayoutView is the id for NestedScrollView , holding the main contents of the activity.

- 19
- 2
You can use my concept if you want that i used in AlertDialog with Blur background in possition center
My approach
- Take a screen shot
- Programtically animate dim/blur screen shot
- Get currant window using a dialog witch does not have any content
- Attach screen shot with effect
- Display real view i wanted to display
Here i have a class for take an image of the background as a bitmap
public class AppUtils {
public static Bitmap takeScreenShot(Activity activity) {
View view = activity.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap b1 = view.getDrawingCache();
Rect frame = new Rect();
activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
int statusBarHeight = frame.top;
Display display = activity.getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
Bitmap b = Bitmap.createBitmap(b1, 0, statusBarHeight, width, height - statusBarHeight);
view.destroyDrawingCache();
return b;
}
}
Congrats now you have a darken/dim image same as your background
Then your requirement is to dim not blur like mine so you can pass this bitmap to below method,
public static Bitmap changeBitmapContrastBrightness(Bitmap bmp, float contrast, float brightness) {
ColorMatrix cm = new ColorMatrix(new float[]
{
contrast, 0, 0, 0, brightness,
0, contrast, 0, 0, brightness,
0, 0, contrast, 0, brightness,
0, 0, 0, 1, 0
});
Bitmap ret = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), bmp.getConfig());
Canvas canvas = new Canvas(ret);
Paint paint = new Paint();
paint.setColorFilter(new ColorMatrixColorFilter(cm));
canvas.drawBitmap(bmp, 0, 0, paint);
return ret;
}
Now use a fake dialog / dialog withOut a background/content only to get the window (Check my questions implementation you can understand that )
Window window = fakeDialogUseToGetWindowForBlurEffect.getWindow();
window.setBackgroundDrawable(draw); // draw is bitmap that you created
after this you can show your real view.In my case i display an alert you can display whatever your view and remember to remove/gone that alert when your real view goes out from the screen!
Quick out put : (background can be customized as you want,not only dim)
Use this style and apply to your dialog.
PS: this style also works perfectly in Android 6.0, 6.1 and 7.0.
<style name="MaterialDialogSheet" parent="@android:style/Theme.Dialog">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowNoTitle">true</item>
<item name="android:backgroundDimEnabled">true</item>
<item name="android:windowIsFloating">false</item>
<item name="android:windowAnimationStyle">@style/MaterialDialogSheetAnimation</item>
</style>
<style name="MaterialDialogSheetAnimation">
<item name="android:windowEnterAnimation">@anim/popup_show</item>
<item name="android:windowExitAnimation">@anim/popup_hide</item>
</style>
And use as:
final Dialog mBottomSheetDialog = new Dialog(mActivity, R.style.MaterialDialogSheet);
Thanks.

- 388
- 7
- 15
-
@tir38 don't judge anyone without knowing an issue. they mentioned without using Fragment Dialog. you better answer that question without downvoting other's answer. – Harsh Dalwadi Jan 12 '17 at 05:11
-
1
-
In case the view implementing the BottomSheetBehavior
is inside a distinct activity you can use the following solution
For making the background of your activity transparent + dimmed add following style to your activity
<style name="Your.Transparent.Style">
<!-- Found no solution for setting the status bar color to fully transparent
from within the style. Had to resort to programmatically setting -->
<item name="android:windowBackground">@color/transparent</item>
<item name="android:backgroundDimEnabled">true</item>
</style>
Inside your AndroidManifest.xml set the activity theme
<activity
android:name="your.activity"
android:theme="@style/Your.Transparent.Style" />
Setting the status bar color to fully transparent (only working for API >= 21)
// Inside your activity's onCreate
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStatusBarTransparent(window)
fun setStatusBarTransparent(window: Window) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
window.statusBarColor = Color.TRANSPARENT
}
}
And finally for hiding the bottom sheet when clicking outside of sheet content, extend the BottomSheetBehavior
class AutoCloseBottomSheetBehavior<V : View>(
context: Context,
attrs: AttributeSet
) : BottomSheetBehavior<V>(context, attrs) {
@SuppressLint("ClickableViewAccessibility")
override fun onLayoutChild(parent: CoordinatorLayout, child: V, layoutDirection: Int): Boolean {
parent.setOnTouchListener { _, event ->
if (event.action == MotionEvent.ACTION_DOWN) {
val outRect = Rect()
child.getGlobalVisibleRect(outRect)
if (!outRect.contains(event.rawX.toInt(), event.rawY.toInt())) {
state = STATE_HIDDEN
return@setOnTouchListener true
}
}
return@setOnTouchListener false
}
return super.onLayoutChild(parent, child, layoutDirection)
}
}
And set it for your view's behavior
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.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"
>
<Your.View.Acting.As.BottomSheet
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior=".your.path.AutoCloseBottomSheetBehavior" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

- 495
- 5
- 16