Bottom Sheets – Material Components for Android

Android Bottom Sheet is the Android Materiel Design Components which slides up from the bottom of the screen. Also, part of the material design components. Bottom sheets are displayed as a result of the user-triggered action, and also it can reveal additional content by swiping up.

Already, I have explained about some of the material components in details. check below,

Sliders – Material Component For Android

ShapeableImageView – Material Components For Android

Android Chips – Material Component For Android

Android Snackbar Example

Types of Bottom Sheets

There are two types of Bottom Sheets available in android:

Persistent bottom sheets

BottomSheetBehavior is applied to a child of CoordinatorLayout to make that child a persistent bottom sheet.

The Persistent bottom sheets display in-app content. It will be displayed at the bottom of the screen making some portion of the content visible.

Modal Bottom Sheets

Modal Bottom Sheet

slides up from bottom of the screen to reveal more content. It’s a dialog which are alternatives to content choosers, simple menus or dialog. Used to present deep-linked content from other apps.

Lets see both bottom sheets in details.

This is my example demo using bottom sheets in android.

Persistent bottom sheets with example

As mentioned above, bottom sheets part of the android material design library. Make sure you have included the library in your project.

    implementation 'com.google.android.material:material:1.2.0'

BottomSheetBehavior is a type of layout_behavior used for persistent bottom sheets. It requires setting CoordinatorLayout as the root element of that layout.

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:background="@android:color/darker_gray">

    <include layout="@layout/layout_persistent_bottomsheet"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

Adding the xml attribute app:layout_behavior:android.support.design.widget.BottomSheetBehavior to the child view.

<androidx.constraintlayout.widget.ConstraintLayout 
    android:id="@+id/bottomSheet"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@android:color/white"
    app:behavior_hideable="false"
    app:behavior_peekHeight="50dp"
    app:behavior_skipCollapsed="true"
    app:layout_behavior="@string/bottom_sheet_behavior"/>

attributes

behavior_peekHeight – The initial “peek” (collapsed state) height of the sheet. The default value is auto, which sets the peek height at the 16:9 ratio keyline of the parent container.

behavior_hideable – Determines whether or not the sheet can be hidden when using a drag down gesture.The default value is false for Standard Bottom Sheets and true for Modal Bottom Sheets.

behavior_draggable – Determines whether or not the sheet can be collapsed/expanded when using a drag gesture.The default value is true.

behavior_skipCollapsed – Determines whether or not the collapsed state should be ignored when hiding the sheet. This has no effect if behavior_hideable is not set to true. The default value is false.

Setting bottom sheets attributes programatically

val standardBottomSheetBehavior = BottomSheetBehavior.from(bottomSheet)
        standardBottomSheetBehavior.isHideable = false
        standardBottomSheetBehavior.peekHeight = 50
        standardBottomSheetBehavior.isDraggable = true
        standardBottomSheetBehavior.skipCollapsed = false

Bottom sheets states:

Bottom sheets have 5 states:

  • STATE_COLLAPSED – The bottom sheet is visible but only showing its peek height.
  • STATE_EXPANDED – The bottom sheet is visible and its maximum height and it is neither dragging or settling (see below).
  • STATE_DRAGGING – Sheet can be collapsed/expanded when using a drag gesture.
  • STATE_SETTLING – The bottom sheet is settling to specific height after a drag/swipe gesture. This will be the peek height, expanded height, or 0, in case the user action caused the bottom sheet to hide.
  • STATE_HIDDEN – The bottom sheet is no longer visible.
  • STATE_HALF_EXPANDED – The sheet is half-expanded (only applicable if behavior_fitToContents has been set to false).

changing the bottom sheets state programatically,

val standardBottomSheetBehavior = BottomSheetBehavior.from(bottomSheet)
        standardBottomSheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN
        //or
        standardBottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
        //or
        standardBottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
        //or
        standardBottomSheetBehavior.state = BottomSheetBehavior.STATE_DRAGGING
        //or
        standardBottomSheetBehavior.state = BottomSheetBehavior.STATE_SETTLING
        //or
        standardBottomSheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN
        //or
        standardBottomSheetBehavior.state = BottomSheetBehavior.STATE_HALF_EXPANDED

Handling bottom sheets callbacks

val standardBottomSheetBehavior = BottomSheetBehavior.from(bottomSheet)
        
        standardBottomSheetBehavior.addBottomSheetCallback(object : BottomSheetCallback() {

            override fun onSlide(bottomSheet: View, slideOffset: Float) {

            }

            override fun onStateChanged(bottomSheet: View, newState: Int) {
    
            }
        })

In the onStateChanged callback, the newState parameter will be the current state of the bottom sheets.

In the onSlide callback, the slideOffset parameter is a Float value in the [-1.0, 1.0] range. Hidden state is -1.0, collapsed state is 0.0 and expanded state is 1.0. The value interpolates linearly and increases as the sheet moves upwards.

Modal Bottom Sheets with example

Modal Bottom Sheets are not part of view layout like Persistent sheets. Instead, they will be shown dynamically using BottomSheetDialog or BottomSheetDialogFragment.

Before creating our BottomSheetDialogFragment however, let’s create the layout for the dialog.

layout_modal_bottomsheet.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">


    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/textCreateNew"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        android:text="Create new"
        style="@style/TextAppearance.AppCompat.Large"
        android:layout_margin="8dp"/>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        app:layout_constraintTop_toBottomOf="@+id/textCreateNew"
        app:layout_constraintStart_toStartOf="parent"
        tools:listitem="@layout/adapter_create_new"
        tools:itemCount="7"
        app:spanCount="3"
        app:layoutManager="androidx.recyclerview.widget.GridLayoutManager" />

</androidx.constraintlayout.widget.ConstraintLayout>

design for this xml:

layout_modal_bottomsheet design

I am using recyclerview to display all the items in bottom sheets dialog fragment.

I have explained recyclerview in details in my another post.

Recyclerview Android Example

We need to create a class that inherits from BottomSheetDialogFragment.

Lets create MyBottomSheetDialogFragment with recyclerview.

class MyBottomSheetDialogFragment : BottomSheetDialogFragment() {

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.layout_modal_bottomsheet, container, false)
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)


        val items = mutableListOf<Item>()
        items.add(Item("Folder",R.drawable.ic_baseline_create_new_folder_24))
        items.add(Item("File",R.drawable.ic_baseline_insert_drive_file_24))
        items.add(Item("Photo",R.drawable.ic_baseline_add_a_photo_24))
        items.add(Item("Post",R.drawable.ic_baseline_post_add_24))
        items.add(Item("Poll",R.drawable.ic_baseline_poll_24))
        items.add(Item("Group",R.drawable.ic_baseline_group_add_24))
        items.add(Item("Alarm",R.drawable.ic_baseline_alarm_add_24))
        items.add(Item("Library",R.drawable.ic_baseline_library_add_24))


        recyclerview.layoutManager = GridLayoutManager(context, 3)
        val adapter = RecyclerviewAdapter(items)
        recyclerview.adapter = adapter

    }
}

Showing a modal bottom sheets

To show a modal bottom sheet, create MyBottomSheetDialogFragment instance and call the show() method on that class.

MyBottomSheetDialogFragment().apply {
                show(supportFragmentManager, tag)
            }

Note that we did not set the behavior for the modal sheet to be hideable, nor did we set the peek height. The modal bottom sheet automatically computes appropriate values for both peek height and expanded height.

You can download this example on GITHUB.

Conclusion

Thanks for reading.

Please share if you like it. Also, don’t forget to share your feedback on comments.

Leave a Reply

Your email address will not be published. Required fields are marked *