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.
A view can be displayed as bottom sheet by attaching bottom sheet behavior to it. Bottom sheet behavior extends Behavior which has methods that coordinator layout calls to provide behavior to child views in response to motion events and positional changes of child views. In order to implement bottom sheet behavior in your app, the view you want to show as bottom sheet needs to be a direct child of coordinator layout.
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.
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.
Open build.gradle file and add support design.
dependencies { ... implementation 'com.android.support:design:27.1.0' }
Programmatically show Bottom Sheet
Following is layout for MainActivity.
<?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" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- Content --> <android.support.v4.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="match_parent" android:padding="5dp" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:layout_gravity="center" android:gravity="center"> <TextView android:textSize="20dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Show BottomSheet" android:onClick="expandBs"/> </LinearLayout> </android.support.v4.widget.NestedScrollView> <!-- BottomSheet --> <android.support.v4.widget.NestedScrollView android:id="@+id/bs" android:layout_width="match_parent" android:layout_height="200dp" android:background="@color/colorPrimaryDark" app:layout_behavior="android.support.design.widget. BottomSheetBehavior"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="5dp" android:gravity="center"> <TextView android:id="@+id/tvInner" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@android:color/white" android:text="BottomSheet" android:textSize="25dp"/> </LinearLayout> </android.support.v4.widget.NestedScrollView> </android.support.design.widget.CoordinatorLayout>
There are few important attributes.
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.In a collapsed state, bottom sheet is not visible to users. If you want to let users know that there exists a bottom sheet on the screen, then some part of bottom sheet can be displayed by setting the peek height of bottom sheet using setPeekHeight
method of bottom sheet behavior object.
You can handle bottom sheet events by implementing BottomSheetCallback
callback methods. BottomSheetCallback
has two call back methods. Method onStateChanged
is called when bottom sheet’s state changes, for example, from collapsed state to expanded state. Another callback method onSlide
is called when bottom sheet is dragged up or down.
Following is the MainActivity.
public class BottomSheetActivity extends AppCompatActivity { private BottomSheetBehavior bottomSheet = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_bottom_sheet); bottomSheet = BottomSheetBehavior.from( findViewById(R.id.bs)); bottomSheet.setHideable(true); bottomSheet.setState(BottomSheetBehavior.STATE_HIDDEN); bottomSheet.setBottomSheetCallback(bottomSheetCallBack); } public void expandBs(View v){ bottomSheet.setState(BottomSheetBehavior.STATE_EXPANDED); } private BottomSheetBehavior.BottomSheetCallback bottomSheetCallBack = new BottomSheetBehavior .BottomSheetCallback(){ public void onSlide (View bottomSheet, float slideOffset){ TextView tvInner = bottomSheet.findViewById(R.id.tvInner); if(slideOffset < 0.4){ tvInner.setText("Show more"); }else{ tvInner.setText("Full info"); } } public void onStateChanged (View bottomSheet, int newState){ TextView tvInner = bottomSheet.findViewById(R.id.tvInner); switch (newState) { case BottomSheetBehavior.STATE_HIDDEN: tvInner.setText("STATE_HIDDEN"); break; case BottomSheetBehavior.STATE_EXPANDED: tvInner.setText("STATE_EXPANDED"); break; case BottomSheetBehavior.STATE_COLLAPSED: tvInner.setText("STATE_COLLAPSED"); break; case BottomSheetBehavior.STATE_DRAGGING: tvInner.setText("STATE_DRAGGING"); break; case BottomSheetBehavior.STATE_SETTLING: tvInner.setText("STATE_SETTLING"); break; } } }; }
Result
Show Bottom Sheet on slide up
We can add app:behavior_peekHeight
to layout and use slide up to show Bottom Sheet.
<!-- BottomSheet --> <android.support.v4.widget.NestedScrollView android:id="@+id/bs" android:layout_width="match_parent" android:layout_height="200dp" android:background="@color/colorPrimaryDark" app:behavior_peekHeight="50dp" app:layout_behavior="android.support.design.widget.BottomSheetBehavior"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="5dp" android:gravity="center"> <TextView android:id="@+id/tvInner" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@android:color/white" android:text="BottomSheet" android:textSize="25dp"/> </LinearLayout> </android.support.v4.widget.NestedScrollView>
Modal Bottom Sheet or android bottom sheet dialog
Design support library provides BottomSheetDialogFragment
and BottomSheetDialog
classes to enable the creation of bottom sheet dialog. To create bottom sheet dialog, create a class which extends BottomSheetDialogFragment
and override setupDialog
method. In setupDialog
method, inflate layout for bottom sheet dialog using view and set the dialog content.
Following is example of MainActivity.
public class MainActivity extends AppCompatActivity { private BottomSheetBehavior bottomSheet = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void expandBs(View v){ ExampleOfBottomSheetDialogFragment frg = ExampleOfBottomSheetDialogFragment.newInstance("BottomSheetDialogFragment"); frg.show(getSupportFragmentManager(), frg.getTag()); } }
Following is layout for MainActivity.
<?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="wrap_content" android:background="@color/colorPrimary" android:orientation="vertical" android:padding="5dp" android:layout_gravity="center"> <TextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@android:color/white" android:textSize="25dp" android:layout_marginBottom="50dp"/> </LinearLayout>
Following is example of BottomSheetDialogFragment.
public class ExampleOfBottomSheetDialogFragment extends BottomSheetDialogFragment { static String KEY_STRING = "KEY_STRING"; static ExampleOfBottomSheetDialogFragment newInstance(String val) { ExampleOfBottomSheetDialogFragment frg = new ExampleOfBottomSheetDialogFragment(); Bundle args = new Bundle(); args.putString(KEY_STRING, val); frg.setArguments(args); return frg; } @SuppressLint("RestrictedApi") @Override public void setupDialog(Dialog dialog, int style) { super.setupDialog(dialog, style); String val = getArguments().getString(KEY_STRING); View v = View.inflate(getContext(), R.layout.bottom_sheet_dialog_fragment, null); TextView tv = v.findViewById(R.id.tv); tv.setText(val); dialog.setContentView(v); } }
Following is layout for BottomSheetDialogFragment.
<?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="wrap_content" android:background="@color/colorPrimary" android:orientation="vertical" android:padding="5dp" android:layout_gravity="center"> <TextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@android:color/white" android:textSize="25dp" android:layout_marginBottom="50dp"/> </LinearLayout>
Result