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.

android-bottom-sheet-tutorial

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.

android-persistent-bottom-sheet

> 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.

android-modal-bottom-sheet

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.

android-bottom-sheet-persistent-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.

android-modal-bottom-sheet-dialog-fragment

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
  • Sujeet Kumar Mehta

    nice article. I was waiting for this

  • Ravikant paudel

    Thanks very much.
    keep on posting .

  • tigani

    Hi @ravi8x: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

  • Prashant Kankayya

    Superb Tutorial @ravi8x:disqus , U posted on a right time. I desperately needed this. Thank’s a lot.

    • Everybody says same thing 😀

      Have a good day!

  • KC Raju Vysyaraju

    Thank you Ravi. Keep posting …
    Waiting for more examples using Material Design

  • Ziigic

    Awesome 🙂

  • Zakaria Mansoor

    Can’t wait to see more, thanks (Y)

  • Aryan Jalan

    Thanks a lot Sir for providing such a useful codes with real time made applications…..

  • Prasanth S

    Awesome Ravi. Keep posting..

  • shivam Kapoor

    Awesome bro keep posting tutorials

  • Raj Parmar

    Thnxs Man.. Your Tutorials helped me a lot in almost all the topics. Keep posting 🙂

  • sam ana

    Great tut! Thanks for posting

  • Prateek Kapoor

    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?

  • Morton

    Awesome tutorial, please posting more !

  • Jaswant Singh Sodha Rajput

    great tutorial

  • Jaswant Singh Sodha Rajput

    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?

      • Jaswant Singh Sodha Rajput

        Yes i also tried recyclerview.setNestedScrollingEnabled(false)
        And i also tried on recyclerview app layout_behavior(appbar_scrolling_view_behavior)

  • Excellent Post.

    Thanks Ravi

  • Mayur Musrif

    As always, your explanation is very Laconic. Nice Example. Keep it up !!!

  • Udit

    Hi Ravi, in Modal Bottom Sheet, bottom sheet expands on sliding up. How to control that?
    Thanks.

  • Xsonz

    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

  • cmcoffee91

    sheetBehavior object is null. It’s saying that it can’t call that method because the object is null basically.

  • manoj

    Hi Ravi,
    how to give margins for the bottomsheet?

  • Prasanth M

    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

    • Atrijit Hazra

      you cant pass the file only u can pass is the path of the file.

  • Murlikrishna

    thanks for this tutorial, your tutorials are very helpful and detailed always…keep posting 🙂

  • Natansh Pandya

    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?

    • Faisal Ahmed

      same

      • Natansh Pandya

        just add
        android:clickable=”true”
        to the root view of the bottom sheet layout

  • Faisal Ahmed

    I am having this same problem. was there a solution?

    • Natansh Pandya

      just add
      android:clickable=”true”
      to the root view of the bottom_layout.xml

  • Deep Dave

    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"

      • Deep Dave

        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

  • Zakaria Mehimda

    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.

  • Ather Sajjad

    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.

    • Atrijit Hazra

      fixed bottom sheet width when the view is in collapse mode and give the same as bottom margin to your recycler view

  • srinath adepu

    Can you please comment on pros and cons of BottomSheetDialog and BottomSheetFragment ? Since both solves the same purpose.

  • Jayant Bhalla

    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?

  • Sandeep Kumar

    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..

  • Atrijit Hazra

    Use intent and let it choose the appropriate one for you

  • Natansh Pandya

    How to round the corners of the bottom sheet layout ?

  • Saandeep Jogiparti

    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.

  • Tuấn Phạm Hoàng

    how to fixed button start at bottom of dialog when dialog expand/hide ?

  • Aniket Modker

    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?

  • Vitalii

    Thank you Ravi, very helpful and well structured guide, keep making as more familiar with Android! 🙂