One of the most significant changes to Android design was introduced during the 2014 Google I/O conference, material design. Even though Google had introduced a set of guidelines for their new design philosophy, developers were responsible for implementing the new patterns from scratch.
As with many things in software development, the Design support library improved with time, adding support for bottom sheets with the 23.2 release.
In this tutorial, we are going to learn how to implement bottom sheets in out app. We are going to use two types of bottom sheets :
1. Persistent Bottom Sheet : Persistent bottom sheets remain visible on the screen. You can convert any view in your layout to a persistent bottom sheet.
2. Modal Bottom Sheet : Modal bottom sheets are dialogs which are alternatives to content choosers, simple menus, and dialogs.
1. Create a new project in Android Studio by navigating to File ⇒ New ⇒ New Project and fill required details. By default my activity is MainActivity.java.
2. Open build.gradle and include this libraries show below:
1 |
compile 'com.android.support:design:24.2.0' |
To implement the bottom sheet, you need to import the Design support library into your project, with a minimum version of 23.2.
3. Once you have synced your project with the Design support library, you can open the layout file that needs to include a bottom sheet. Create activity_main.xml and add the following code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
<?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:fitsSystemWindows="true" tools:context="com.bottomsheet_demo.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" /> <!-- Bottom Sheet Dialog Content @set app:layout_behavior = "android.support.design.widget.BottomSheetBehavior" --> <android.support.v4.widget.NestedScrollView android:id="@+id/bottom_sheet" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#EEEEEE" android:clipToPadding="true" app:layout_behavior="android.support.design.widget.BottomSheetBehavior"> <include layout="@layout/bottom_sheet_content" /> </android.support.v4.widget.NestedScrollView> </android.support.design.widget.CoordinatorLayout> |
There are a few key points that you need to take care:
1. To use the bottom sheets widget, you must use a CoordinatorLayout
container for the views.
2. As you notice that there is a NestedScrollView
containing a LinearLayout
. While any container view can be used in a bottom sheet, scrolling can only properly occur if you use a container that supports nested scrolling, such as the NestedScrollView
or a RecyclerView
.
3. For a container to be recognized by the Design support library as a bottom sheet container, you need to include the layout_behavior
attribute and give it a value of android.support.design.widget.BottomSheetBehavior
. You can see this used above in the NestedScrollView
.
4. Now create content_main.xml that used in above xml file and add the below code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<?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:id="@+id/content_main" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:context="com.bottomsheet_demo.MainActivity" tools:showIn="@layout/activity_main"> <android.support.v7.widget.AppCompatButton android:id="@+id/bottom_sheet_dialog" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/show_bottom_sheet_dialog" /> <android.support.v7.widget.AppCompatButton android:id="@+id/bottom_sheet_dialog_fragment" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/show_bottom_sheet_dialog_fragment" /> </LinearLayout> |
5. Now the content that you want to show for bottom sheet, for this create new xml file naming bottom_sheet_content.xml and add whatever you like,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<?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:padding="16dp"> <android.support.v7.widget.AppCompatTextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingBottom="10dp" android:text="This is Bottom Sheet Demo." android:textColor="#000000" android:textSize="16sp" /> <android.support.v7.widget.AppCompatButton android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Demo Button" /> </LinearLayout> |
6. For your bottom sheet to be displayable, you need to create a BottomSheetBehavior
. This is created by getting a reference to the container view and calling BottomSheetBehavior.from()
on that container.
1 |
private BottomSheetBehavior mBottomSheetBehavior; |
1 |
mBottomSheetBehavior = BottomSheetBehavior.from(bottomSheet); |
At start set the state of bottom sheet as Collapse Mode and peek height as 0.
1 2 |
mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); mBottomSheetBehavior.setPeekHeight(0); |
There are five states of BottomSheet behavior:
Now to display your Bottom Sheet you have to set the Expanded Mode.
1 |
mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); |
If you’d like to receive callbacks of state changes, you can add a BottomSheetCallback:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
//If you want to handle callback of Sheet Behavior you can use below code mBottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { @Override public void onStateChanged(@NonNull View bottomSheet, int newState) { switch (newState) { case BottomSheetBehavior.STATE_COLLAPSED: Log.d(TAG, "State Collapsed"); break; case BottomSheetBehavior.STATE_DRAGGING: Log.d(TAG, "State Dragging"); break; case BottomSheetBehavior.STATE_EXPANDED: Log.d(TAG, "State Expanded"); break; case BottomSheetBehavior.STATE_HIDDEN: Log.d(TAG, "State Hidden"); break; case BottomSheetBehavior.STATE_SETTLING: Log.d(TAG, "State Settling"); break; } } @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { } }); |
Till here we successfully implemented Bottom Sheet Dialog. Now in next step we will learn how to implement BottomSheetDialogFragment.
7. To implement Bottom Sheet Dialog Fragment, create a class naming BottomSheetFragment.java and extend it with BottomSheetDialogFragment.
Within the setupDialog()
method, you can inflate a new layout file and retrieve the BottomSheetBehavior
of the container view in your Activity
. Once you have the behavior, you can create and associate a BottomSheetCallback
with it to dismiss the Fragment
when the sheet is hidden.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
package com.bottomsheet_demo; import android.app.Dialog; import android.support.annotation.NonNull; import android.support.design.widget.BottomSheetBehavior; import android.support.design.widget.BottomSheetDialogFragment; import android.support.design.widget.CoordinatorLayout; import android.view.View; /** * Created by sonu on 30/08/16. */ public class BottomSheetFragment extends BottomSheetDialogFragment { //Bottom Sheet Callback private BottomSheetBehavior.BottomSheetCallback mBottomSheetBehaviorCallback = new BottomSheetBehavior.BottomSheetCallback() { @Override public void onStateChanged(@NonNull View bottomSheet, int newState) { if (newState == BottomSheetBehavior.STATE_HIDDEN) { dismiss(); } } @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { } }; @Override public void setupDialog(Dialog dialog, int style) { super.setupDialog(dialog, style); //Get the content View View contentView = View.inflate(getContext(), R.layout.fragment_bottom_sheet, null); dialog.setContentView(contentView); //Set the coordinator layout behavior CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) ((View) contentView.getParent()).getLayoutParams(); CoordinatorLayout.Behavior behavior = params.getBehavior(); //Set callback if (behavior != null && behavior instanceof BottomSheetBehavior) { ((BottomSheetBehavior) behavior).setBottomSheetCallback(mBottomSheetBehaviorCallback); } } } |
Now, you can call show()
on an instance of your Fragment
to display it in the bottom sheet.
1 2 |
BottomSheetDialogFragment bottomSheetDialogFragment = new BottomSheetFragment(); bottomSheetDialogFragment.show(getSupportFragmentManager(), "Bottom Sheet Dialog Fragment"); |
8. For BottomSheetFragment class create xml file naming fragment_bottom_sheet.xml and add the below code to it.
1 2 3 4 5 6 7 8 |
<?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"> <include layout="@layout/bottom_sheet_content" /> </LinearLayout> |
9. Full source of MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
package com.bottomsheet_demo; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.design.widget.BottomSheetBehavior; import android.support.design.widget.BottomSheetDialogFragment; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; public class MainActivity extends AppCompatActivity implements OnClickListener { private static final String TAG = MainActivity.class.getSimpleName(); private BottomSheetBehavior mBottomSheetBehavior; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); //Find bottom Sheet ID View bottomSheet = findViewById(R.id.bottom_sheet); mBottomSheetBehavior = BottomSheetBehavior.from(bottomSheet); //By default set BottomSheet Behavior as Collapsed and Height 0 mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); mBottomSheetBehavior.setPeekHeight(0); //If you want to handle callback of Sheet Behavior you can use below code mBottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { @Override public void onStateChanged(@NonNull View bottomSheet, int newState) { switch (newState) { case BottomSheetBehavior.STATE_COLLAPSED: Log.d(TAG, "State Collapsed"); break; case BottomSheetBehavior.STATE_DRAGGING: Log.d(TAG, "State Dragging"); break; case BottomSheetBehavior.STATE_EXPANDED: Log.d(TAG, "State Expanded"); break; case BottomSheetBehavior.STATE_HIDDEN: Log.d(TAG, "State Hidden"); break; case BottomSheetBehavior.STATE_SETTLING: Log.d(TAG, "State Settling"); break; } } @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { } }); //Implement click listeners findViewById(R.id.bottom_sheet_dialog).setOnClickListener(this); findViewById(R.id.bottom_sheet_dialog_fragment).setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.bottom_sheet_dialog: //Check the current state of bottom sheet if (mBottomSheetBehavior.getState() == BottomSheetBehavior.STATE_COLLAPSED) //If state is in collapse mode expand it mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); else //else if state is expanded collapse it mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); break; case R.id.bottom_sheet_dialog_fragment: //Show the Bottom Sheet Fragment BottomSheetDialogFragment bottomSheetDialogFragment = new BottomSheetFragment(); bottomSheetDialogFragment.show(getSupportFragmentManager(), "Bottom Sheet Dialog Fragment"); break; } } } |
10. That’s all you have to done.
Thanks. 🙂
Subscribe to us and get the latest news.
1 Comment
onetouchcode.com
Thursday, December 29th, 2016Good article, I have also written an article on http://onetouchcode.com/bottomsheetdialog-android/ . Hopefully it help other Android developers