Android Bottom Sheet component slides up from the bottom showing more relevant content. You can notice bottom sheets in apps like map apps (bottom sheet reveals location, directions information), music players (Play bar sticks to bottom and opens when swipe up). The bottom sheet is the component of android design support library.
In this article we are going to learn integrating a basic Bottom Sheet and types of bottom sheets. Before getting started refer Google material design guidelines about Bottom Sheet for design specs.
1. The Types of Bottom Sheets
There are two types of bottom sheets, Persistent Bottom Sheet and Modal Bottom Sheet.
> Persistent Bottom Sheet: The Persistent bottom sheet displays in-app content. It will be displayed at the bottom of the screen making some portion of the content visible. When activated it opens the full content. The elevation of the persistent bottom sheet is same as app making it part of the app. Below is the example of persistent bottom sheet of Google Maps app.
> Modal Bottom Sheet: Modal bottom sheets have higher elevation than the app. These usually replaces menus or dialogs. Generally modal bottom sheets used to show deep-linked content from other apps. Below are the examples of modal bottom sheet of Google Drive app.
Now let’s start implementing the Bottom Sheet by creating a new project in Android Studio.
2. Creating New Project
1. Create a new project in Android Studio from File ⇒ New Project and select Basic Activity from templates.
2. Download this res folder and add the drawables to your project’s res. This folder contains necessary drawables required for modal bottom sheet.
3. Open build.gradle file and add support design and ButterKnife dependencies. Here ButterKnife is completely optional. It’s used for view binding and is not related to bottom sheet in anyway.
dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:26.1.0' implementation 'com.android.support:design:26.1.0' // butter knife compile 'com.jakewharton:butterknife:8.8.1' annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1' }
Now we’ll create the layout needed for bottom sheet. Here I am trying to keep simple order summary which contains list of items ordered and a button to proceed the payment.
4. Create an xml layout under res ⇒ layout named bottom_sheet.xml and add below code. Here few important attributes has to observed.
> app:layout_behavior: This attribute makes the layout act as bottom sheet. The value should be android.support.design.widget.BottomSheetBehavior
> app:behavior_peekHeight: This is the height of the bottom sheet when it is minimized.
> app:behavior_hideable: Makes bottom sheet hidden when swiped it down.
<?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/bottom_sheet" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#fff" android:orientation="vertical" android:padding="@dimen/activity_margin" app:behavior_hideable="true" app:behavior_peekHeight="56dp" app:layout_behavior="android.support.design.widget.BottomSheetBehavior"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_gravity="center_vertical" android:weightSum="3"> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/activity_margin" android:layout_weight="2" android:text="Order Details" android:textColor="#444" android:textSize="18dp" android:textStyle="bold" /> <TextView android:layout_width="0dp" android:gravity="right" android:layout_height="wrap_content" android:layout_weight="1" android:textStyle="bold" android:textSize="15dp" android:text="₹435.00"></TextView> </LinearLayout> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Chicken Fried Rice 1x1" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Paneer Tikka 1x2" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="@dimen/activity_margin" android:text="Delivery Address" android:textColor="#444" android:textStyle="bold" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Flat No 404, Skyline Apartments, Vizag - 500576" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="30dp" android:background="#000" android:foreground="?attr/selectableItemBackground" android:text="PROCEED PAYMENT" android:textColor="#fff" /> </LinearLayout>
5. Now include the bottom_sheet.xml in your main activity layout. Open layout files of main activity (activity_main.xml and content_main.xml) modify as below. I also kept three buttons to showcase the other bottom sheet examples.
<?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" android:background="#efefef" tools:context="info.androidhive.bottomsheet.MainActivity"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:popupTheme="@style/AppTheme.PopupOverlay" /> </android.support.design.widget.AppBarLayout> <include layout="@layout/content_main" /> <!-- Adding bottom sheet after main content --> <include layout="@layout/bottom_sheet" /> </android.support.design.widget.CoordinatorLayout>
<?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" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:context="info.androidhive.bottomsheet.MainActivity" tools:showIn="@layout/activity_main"> <Button android:id="@+id/btn_bottom_sheet" android:layout_width="wrap_content" android:layout_marginTop="@dimen/activity_margin" android:layout_gravity="center_horizontal" android:layout_height="wrap_content" android:text="Show Bottom Sheet" /> <Button android:id="@+id/btn_bottom_sheet_dialog" android:layout_width="wrap_content" android:layout_marginTop="@dimen/activity_margin" android:layout_gravity="center_horizontal" android:layout_height="wrap_content" android:text="Show Bottom Sheet Dialog" /> <Button android:id="@+id/btn_bottom_sheet_dialog_fragment" android:layout_width="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="@dimen/activity_margin" android:layout_height="wrap_content" android:text="Show Bottom Sheet Dialog Fragment" /> </LinearLayout>
6. Now open MainActivity.java and do the below modifications.
> BottomSheetBehavior provides callbacks and make the BottomSheet work with CoordinatorLayout.
> BottomSheetBehavior.BottomSheetCallback() provides callback when the Bottom Sheet changes its state.
> toggleBottomSheet() Opens or closes the bottom sheet on button click.
package info.androidhive.bottomsheet; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.design.widget.BottomSheetBehavior; import android.support.design.widget.BottomSheetDialog; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.View; import android.view.Menu; import android.view.MenuItem; import android.widget.Button; import android.widget.LinearLayout; import android.widget.RelativeLayout; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getSimpleName(); @BindView(R.id.btn_bottom_sheet) Button btnBottomSheet; @BindView(R.id.bottom_sheet) LinearLayout layoutBottomSheet; BottomSheetBehavior sheetBehavior; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); sheetBehavior = BottomSheetBehavior.from(layoutBottomSheet); /** * bottom sheet state change listener * we are changing button text when sheet changed state * */ sheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { @Override public void onStateChanged(@NonNull View bottomSheet, int newState) { switch (newState) { case BottomSheetBehavior.STATE_HIDDEN: break; case BottomSheetBehavior.STATE_EXPANDED: { btnBottomSheet.setText("Close Sheet"); } break; case BottomSheetBehavior.STATE_COLLAPSED: { btnBottomSheet.setText("Expand Sheet"); } break; case BottomSheetBehavior.STATE_DRAGGING: break; case BottomSheetBehavior.STATE_SETTLING: break; } } @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { } }); } /** * manually opening / closing bottom sheet on button click */ @OnClick(R.id.btn_bottom_sheet) public void toggleBottomSheet() { if (sheetBehavior.getState() != BottomSheetBehavior.STATE_EXPANDED) { sheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); btnBottomSheet.setText("Close sheet"); } else { sheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); btnBottomSheet.setText("Expand sheet"); } } }
If you run the project, you can see the bottom sheet displayed at the bottom. This will be considered as Persistent Bottom Sheet.
3. Modal Bottom Sheet – BottomSheetDialog and BottomSheetDialogFragment
Modal Bottom Sheets are not part of view layout like Persistent sheets. Instead, they will be shown dynamically using BottomSheetDialog or BottomSheetDialogFragment. Now let’s see how to implement Modal Bottom Sheets.
7. Create an xml layout named fragment_bottom_sheet_dialog.xml under res ⇒ layout. This layout contains few list items to provide user actions. (Note: Consider using RecyclerView to achieve the list instead of using nested layouts as below).
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="8dp" android:paddingTop="8dp"> <!-- NOTE: This list should be displayed in a list instead of nested layouts --> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:clickable="true" android:foreground="?attr/selectableItemBackground" android:orientation="horizontal" android:paddingBottom="8dp" android:paddingLeft="@dimen/activity_margin" android:paddingRight="@dimen/activity_margin" android:paddingTop="8dp"> <ImageView android:layout_width="24dp" android:layout_height="24dp" android:layout_marginRight="32dp" android:src="@drawable/ic_remove_red_eye_black_24dp" android:tint="#737373" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:text="Preview" android:textColor="#737373" android:textSize="16sp" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:clickable="true" android:foreground="?attr/selectableItemBackground" android:orientation="horizontal" android:paddingBottom="8dp" android:paddingLeft="@dimen/activity_margin" android:paddingRight="@dimen/activity_margin" android:paddingTop="8dp"> <ImageView android:layout_width="24dp" android:layout_height="24dp" android:layout_marginRight="32dp" android:src="@drawable/ic_share_black_24dp" android:tint="#737373" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:text="Share" android:textColor="#737373" android:textSize="16sp" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:clickable="true" android:foreground="?attr/selectableItemBackground" android:orientation="horizontal" android:paddingBottom="8dp" android:paddingLeft="@dimen/activity_margin" android:paddingRight="@dimen/activity_margin" android:paddingTop="8dp"> <ImageView android:layout_width="24dp" android:layout_height="24dp" android:layout_marginRight="32dp" android:src="@drawable/ic_link_black_24dp" android:tint="#737373" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:text="Get link" android:textColor="#737373" android:textSize="16sp" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:clickable="true" android:foreground="?attr/selectableItemBackground" android:orientation="horizontal" android:paddingBottom="8dp" android:paddingLeft="@dimen/activity_margin" android:paddingRight="@dimen/activity_margin" android:paddingTop="8dp"> <ImageView android:layout_width="24dp" android:layout_height="24dp" android:layout_marginRight="32dp" android:src="@drawable/ic_content_copy_black_24dp" android:tint="#737373" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:text="Make a Copy" android:textColor="#737373" android:textSize="16sp" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:clickable="true" android:foreground="?attr/selectableItemBackground" android:orientation="horizontal" android:paddingBottom="8dp" android:paddingLeft="@dimen/activity_margin" android:paddingRight="@dimen/activity_margin" android:paddingTop="8dp"> <ImageView android:layout_width="24dp" android:layout_height="24dp" android:layout_marginRight="32dp" android:src="@drawable/ic_email_black_24dp" android:tint="#737373" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:text="Email a Copy" android:textColor="#737373" android:textSize="16sp" /> </LinearLayout> </LinearLayout>
8. Create a new Fragment from File ⇒ New ⇒ Fragment ⇒ Fragment (Blank) and name it as BottomSheetFragment.java or just a create a class with the same name. Extend this class from BottomSheetDialogFragment.
package info.androidhive.bottomsheet; import android.os.Bundle; import android.support.design.widget.BottomSheetDialogFragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; public class BottomSheetFragment extends BottomSheetDialogFragment { public BottomSheetFragment() { // Required empty public constructor } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_bottom_sheet_dialog, container, false); } }
9. Now as the dialog fragment is ready, open the MainActivity.java and add the below method. Once added, try running the project again and click on other two buttons to open Modal Bottom Sheet Dialog and Fragment
/** * showing bottom sheet dialog */ @OnClick(R.id.btn_bottom_sheet_dialog) public void showBottomSheetDialog() { View view = getLayoutInflater().inflate(R.layout.fragment_bottom_sheet_dialog, null); BottomSheetDialog dialog = new BottomSheetDialog(this); dialog.setContentView(view); dialog.show(); } /** * showing bottom sheet dialog fragment * same layout is used in both dialog and dialog fragment */ @OnClick(R.id.btn_bottom_sheet_dialog_fragment) public void showBottomSheetDialogFragment() { BottomSheetFragment bottomSheetFragment = new BottomSheetFragment(); bottomSheetFragment.show(getSupportFragmentManager(), bottomSheetFragment.getTag()); }
Below is the output of Modal Bottom Sheet.
I hope this article gives clear explanation on Bottom Sheets. Please do comment in comment section below incase of any queries.
Hi there! I am Founder at androidhive and programming enthusiast. My skills includes Android, iOS, PHP, Ruby on Rails and lot more. If you have any idea that you would want me to develop? Let’s talk: ravi@androidhive.info
nice article. I was waiting for this
Thanks 🙂
Thanks very much.
keep on posting .
Sure 🙂
Hi @Ravi Tamada:disqus ..thanks great like always……I used your tut login & reg very helpful….but how to achieve (Forget password) for my users if they forget it….could you tell me an idea about the scenario..thanks in advance
Superb Tutorial @Ravi Tamada:disqus , U posted on a right time. I desperately needed this. Thank’s a lot.
Everybody says same thing 😀
Have a good day!
Thank you Ravi. Keep posting …
Waiting for more examples using Material Design
Yes I am working on it.
Awesome 🙂
Thank you 🙂
Can’t wait to see more, thanks (Y)
😀
Thanks a lot Sir for providing such a useful codes with real time made applications…..
you are most welcome 🙂
Awesome Ravi. Keep posting..
Thanks Prasanth.
Awesome bro keep posting tutorials
Thank you Shivam 🙂
Thnxs Man.. Your Tutorials helped me a lot in almost all the topics. Keep posting 🙂
I am glad Raj 🙂
Great tut! Thanks for posting
You are welcome Sam:)
Hey Ravi, can we reduce the animation time of bottom sheet, as well please specify the way if possible to close the bottom sheet with same effect on the click of a button, i.e. the same effect of swiping down on click of a button?
Awesome tutorial, please posting more !
great tutorial
Thank you
Please Ravi make tutorial on having coordinator layout with Tab Layout, Viewpager and Persistant Bottom Sheet,
Tab Layout having three tabs with fragment and all fragment have a recyclerview, Just like any any Music app plyer,
I tried but problem is recyclerview is not scrolling smoothly
Have you disabled nested scrolling on RecyclerView?
Yes i also tried recyclerview.setNestedScrollingEnabled(false)
And i also tried on recyclerview app layout_behavior(appbar_scrolling_view_behavior)
Have you tried keeping all the views in NestedScrollView and check?
I also tried NestedScrollView and set false to setNestedScrollingEnabled, my fragment has one layout that is recyclerview and put it in NestedScrollView but same problem, i am trying from three days but until no solution, i want to make a music player app and i first tried a Library like persistant bottomsheet name is AndroidSlidingUpPanel. When i removed botttomsheet, recyclerview scrolling smoothtly
Post the screenshot of the app you have achieved. Any code also will be useful to debug the problem.
Thank u so much Ravi.
Problem has solved,
I were showing placeholder image on imageview is very large size image and that is reason of recyclerview was not scrolling smoothly
I am glad the problem is solved 🙂
Have a nice day!
Thank u
https://sites.google.com/site/lokeshurl/bottom-sheet-in-android/bottomsheet-recyclerview
Excellent Post.
Thanks Ravi
You are welcome 🙂
As always, your explanation is very Laconic. Nice Example. Keep it up !!!
Thank you Mayur 🙂
Hi Ravi, in Modal Bottom Sheet, bottom sheet expands on sliding up. How to control that?
Thanks.
Hey Ravi. First of all, great tutorial. I have a question tho. How to make buttons clickable in a
Modal Bottom Sheet version? I can’t seem to figure out how to declare it inside BottomSheetDialogFragment. Any tips in right direction? Thank you
sheetBehavior object is null. It’s saying that it can’t call that method because the object is null basically.
Hi Ravi,
how to give margins for the bottomsheet?
Thank you so much bro….because Androidhive is very helpful for me ….i have one doubt bro …can we pass raw files to next activity screen ? if it’s possible how can i do ? please solve it bro
you cant pass the file only u can pass is the path of the file.
thanks for this tutorial, your tutorials are very helpful and detailed always…keep posting 🙂
You are welcome:) I’ll do my best.
thanks for sharing a great tutorial sir.just one query i successfully implemented Persistent Bottom Sheet.
i have a recyclerview displaying movie posters and on clicking a poster its details pop up on a persistent bottom sheet but the problem i am facing is that when the bottom sheet is fully expanded wherever i click on the bottom sheet the posters beneath them are clicked always. How to solve this problem?
same
just add
android:clickable=”true”
to the root view of the bottom sheet layout
I am having this same problem. was there a solution?
just add
android:clickable=”true”
to the root view of the bottom_layout.xml
Nice tutorial Ravi bhai..
My question may be stupid one But,
Is it possible to display it at top of page instead of bottom..
I haven’t tried. Change the gravity to top and try once.
android:layout_gravity="top"
I dont think it should work ..
in Current code
public class BottomSheetFragment extends BottomSheetDialogFragment {
It is extendinig BottomSheetDialog Fragment.. and i failed to find anything like TopSheetDialogFragment..
Worked with Custom View animation for now.. I am interested if anyone would find something easier like Bottomsheet.
Thanks
Okay
hi ravi can i used this in Navigation DrawerLayout
Both shouldn’t be used. I written few points in the article about choosing between the app navigations.
in content main i have a recycler view and bottom sheet is also there.
Bottom sheet hides the last element of recycler view. Can you please let me know how to
show the last element.
fixed bottom sheet width when the view is in collapse mode and give the same as bottom margin to your recycler view
Can you please comment on pros and cons of BottomSheetDialog and BottomSheetFragment ? Since both solves the same purpose.
hi ravi, can you explain, that how to make the PersistentBottomSheet scroll freely like that in google maps.
also, what to code in the onSlide(…) method of BottomSheetBehavior?
sir, your tutorial was very helpful.. but i one thing more..i want to add more thing in bottomsheet which should be scrollable but when I scroll down the bottom sheet close. In Google Assistance and other apps bottomsheet appears on cliking share button doesnt closes. Help me sir my project is almost to end..
koi help nai bhai ap khud mehnat karo ravi bzy hyn aj or har time help hi na manga karo yuar
Use intent and let it choose the appropriate one for you
How to round the corners of the bottom sheet layout ?
Set a background for your layout…
I have used bottom sheet dialog fragment as mentioned in your layout, its working fine.
I have used a LinerLayout with edit text and button inside bottom sheet dialog. And SOFT_INPUT_ADJUST_RESIZE property to request focus keyboard on start of bottom sheet fragment.
But because of this keyboard is hiding/overlapping the button under the edit text, any help is appreciated.
Did you ever figure out what to do?
Can you post the screenshot of the issue?
how to fixed button start at bottom of dialog when dialog expand/hide ?
i have create a bottom sheet layout and inflate it in bottomsheetdialog fragment now i want to use the listenere of that element. In which activity i can perform that action in Mainactivity or FragmentActivity?
Thank you Ravi, very helpful and well structured guide, keep making as more familiar with Android! 🙂
I’ll do Vitalii 🙂
Thank you very much!!!
do you have a subscription based app example?
how to implement Modal side sheets
@@Ravi Tamada:disqus what if i want to add peek height for the dialog fragment as you have added to bottom sheet
Thank you !!!
how to open BottomSheetDialogFragment fullscreen?
how to show BottomSheetDialogFragment fullscreen?
dialog.getBehavior().setState(BottomSheetBehavior.STATE_EXPANDED);
hi, the bottom sheet doesn’t show when i removed the butterknife can i know why
How to open a camera from bottom sheet button and show the path on base activity on textView
Hi Ravi, Thanks for the nice article.
In my project i was using BottomSheetDialogFragment to show contents, Whenever i show/dismiss alertDialog from this fragment there is a blink on screen. How to fix this issue?
Good introduction!
Two notes for the reader:
1. should use the DialogFragment version instead of just Dialog to avoid leaks (try rotating device and look at LogCat)
2. either the bottom sheet callback or manual action in toggleBottomSheet() can be used for setting button text
it’s not working under androidx
got different errors one by one