This article is about BottomSheet, types of BottomSheet, and how to integrate a basic Bottom Sheet in our Android application.
BottomSheet
A BottomSheet is a component that is used to display some information by sliding the view up from the bottom of the screen and also, you can hide this BottomSheet when the message is conveyed to the users. This is a nice way of conveying some message or performing some task in Android.
Types of BottomSheet
BottomSheets is of two types:
Persistent BottomSheet:
- The Persistent BottomSheet is visible along with other UI components on the screen.
- Initially, some content of this Persistent BottomSheet is visible(you can set the peek height i.e. the initial height of BottomSheet to 0 also) and when you slide it up, then the rest of the content will appear along with the BottomSheet.
The following is an example of Persistent BottomSheet:


Modal BottomSheet:
- Modal bottom sheets present a set of choices while blocking interaction with the rest of the screen.
- Unlike Persistent BottomSheet, it is totally invisible initially, and on certain actions (maybe a button click), it appears from the bottom of the screen.
- It generally contains some list of items and the items of the list correspond to some action.
- Modal bottom sheets are an alternative to inline menus or simple dialogs on mobile and provide room for additional items, longer descriptions, and iconography.
The following is an example of Modal BottomSheet:


States of BottomSheet
Bottom sheets have 5 states and with the help of these states, we can perform various actions according to our needs.
- STATE_COLLAPSED: This state indicates that the BottomSheet is collapsed i.e. the bottom sheet is visible up to its peek height only.
- STATE_EXPANDED: This state indicates that the BottomSheet is fully expanded to its maximum height and all the content of the BottomSheet is visible.
- STATE_DRAGGING: This state indicates that the BottomSheet is dragging either in the upward direction or in the downward direction.
- STATE_SETTLING: This state indicates that the BottomSheet is settling either to the max height or to the peek height. (Sometimes height can be 0 also when behavior_hideable is set to true)
- STATE_HIDDEN: This state indicates that the BottomSheet is hidden i.e. it is possible only when the value of behavior_hideable is set to true. Once, the BottomSheet is hidden, you can’t scroll it to make it visible. To make it visible again, you need to change its state by some action (maybe on some button click).
NOTE: These states are for Persistent BottomSheet.
Creating new project
- Create a new project by going to File ⇒ New Android Project, select Empty Activity, provide app name, select language to kotlin and then finally click on finish.
-
Open app-level build.gradle file, add the dependency of material design, and sync the project.
build.gradle
dependencies {
//material design
implementation 'com.google.android.material:material:1.4.0'
}
Find the latest version of the material design from here.
Persistent BottomSheet Example
1 . The layout file layout_bottom_sheet.xml represents the UI of the Persistent BottomSheet. It consists of two text views, one for the title and one for the description.
layout_bottom_sheet.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/bottomSheet" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/colorPrimaryDark" app:behavior_hideable="false" app:behavior_peekHeight="40dp" app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"> <TextView android:id="@+id/tvTitle" android:layout_width="0dp" android:layout_height="40dp" android:layout_marginStart="16dp" android:layout_marginEnd="16dp" android:gravity="center_vertical" android:text="@string/title" android:textColor="@android:color/white" android:textSize="22sp" android:textStyle="bold" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/tvSubtitle" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_margin="16dp" android:text="@string/description" android:textColor="@android:color/white" android:textSize="16sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/tvTitle" /> </androidx.constraintlayout.widget.ConstraintLayout>
- com.google.android.material.bottomsheet.BottomSheetBehavior : defines the layout behavior.
- behavior_hideable: used to set if the bottom sheet can be hidden totally when we drag it down or not.
- behavior_peekHeight: This is the height up to which the bottom sheet will be visible in the collapsed state.
2. Add layout_bottom_sheet.xml layout to the activity_main.xml file. It consists of three buttons, one for Persistent BottomSheet, one for BottomSheetDialog, and one for BottomSheetDialogFragment.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btnBottomSheet"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:text="Show Bottom Sheet" />
<Button
android:id="@+id/btnBottomSheetDialog"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginStart="12dp"
android:layout_marginTop="60dp"
android:layout_marginEnd="12dp"
android:text="Show Bottom Sheet Dialog" />
<Button
android:id="@+id/btnBottomSheetDialogFragment"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginStart="12dp"
android:layout_marginTop="120dp"
android:layout_marginEnd="12dp"
android:text="Show Bottom Sheet Dialog Fragment" />
<include layout="@layout/layout_bottom_sheet" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Note: BottomSheet is the direct child of the CoordinatorLayout.
3 . The MainActivity contains the following code:
MainActivity.kt
package com.c1ctech.androidbottomsheetexp
import android.os.Bundle
import android.view.View
import android.widget.RelativeLayout
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.layout_bottom_sheet.*
class MainActivity : AppCompatActivity() {
private lateinit var bottomSheetBehavior: BottomSheetBehavior<ConstraintLayout>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet)
bottomSheetBehavior.addBottomSheetCallback(object :
BottomSheetBehavior.BottomSheetCallback() {
override fun onSlide(bottomSheet: View, slideOffset: Float) {
// handle onSlide
}
override fun onStateChanged(bottomSheet: View, newState: Int) {
when (newState) {
BottomSheetBehavior.STATE_COLLAPSED -> Toast.makeText(
this@MainActivity,
"STATE_COLLAPSED",
Toast.LENGTH_SHORT
).show()
BottomSheetBehavior.STATE_EXPANDED -> Toast.makeText(
this@MainActivity,
"STATE_EXPANDED",
Toast.LENGTH_SHORT
).show()
BottomSheetBehavior.STATE_DRAGGING -> Toast.makeText(
this@MainActivity,
"STATE_DRAGGING",
Toast.LENGTH_SHORT
).show()
BottomSheetBehavior.STATE_SETTLING -> Toast.makeText(
this@MainActivity,
"STATE_SETTLING",
Toast.LENGTH_SHORT
).show()
BottomSheetBehavior.STATE_HIDDEN -> Toast.makeText(
this@MainActivity,
"STATE_HIDDEN",
Toast.LENGTH_SHORT
).show()
else -> Toast.makeText(this@MainActivity, "OTHER_STATE", Toast.LENGTH_SHORT)
.show()
}
}
})
btnBottomSheet.setOnClickListener {
if (bottomSheetBehavior.state == BottomSheetBehavior.STATE_EXPANDED) {
bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
} else {
bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
}
}
}
}
- onStateChanged(): override to observe various states of the BottomSheet.
Here, On click of the button, we are changing its state i.e. when it is expanded then we are collapsing it and vice-versa.
4. Run the app, the bottom sheet displayed at the bottom. Observe the various states of the BottomSheet.


Modal BottomSheet Example using BottomSheetDialog
1 . The layout file layout_bottom_sheet_dialog.xml represents the UI of the Modal BottomSheet creating using BottomSheetDialog.
layout_bottom_sheet_dialog.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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" android:padding="10dp"> <RelativeLayout android:id="@+id/rl_edit" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="8dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> <ImageButton android:id="@+id/imgEdit" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentStart="true" android:layout_centerVertical="true" android:layout_marginStart="6dp" android:background="@android:color/transparent" android:src="@drawable/ic_edit" /> <TextView android:id="@+id/tv_edit" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginStart="6dp" android:layout_toRightOf="@+id/imgEdit" android:text="Edit" /> </RelativeLayout> <RelativeLayout android:id="@+id/rl_delete" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:padding="8dp" app:layout_constraintEnd_toEndOf="@+id/rl_edit" app:layout_constraintStart_toStartOf="@+id/rl_edit" app:layout_constraintTop_toBottomOf="@+id/rl_edit"> <ImageButton android:id="@+id/imgDelete" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentStart="true" android:layout_centerVertical="true" android:layout_marginStart="6dp" android:background="@android:color/transparent" android:src="@drawable/ic_delete" /> <TextView android:id="@+id/tv_delete" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginStart="6dp" android:layout_toRightOf="@+id/imgDelete" android:text="Delete" /> </RelativeLayout> <RelativeLayout android:id="@+id/rl_add" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:padding="8dp" app:layout_constraintEnd_toEndOf="@+id/rl_delete" app:layout_constraintStart_toStartOf="@+id/rl_delete" app:layout_constraintTop_toBottomOf="@+id/rl_delete"> <ImageButton android:id="@+id/imgAdd" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentStart="true" android:layout_centerVertical="true" android:layout_marginStart="6dp" android:background="@android:color/transparent" android:src="@drawable/ic_add" /> <TextView android:id="@+id/tv_add" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginStart="6dp" android:layout_toRightOf="@+id/imgAdd" android:text="Add" /> </RelativeLayout> </androidx.constraintlayout.widget.ConstraintLayout>
2 . In MainActivity, add the below function which is invoked on BottomSheetDialog button click.
//setting clicklistener
btnBottomSheetDialog.setOnClickListener { showBottomSheetDialog() } private fun showBottomSheetDialog() { val dialog = BottomSheetDialog(this) dialog.setContentView(R.layout.layout_bottom_sheet_dialog) val RLEdit = dialog.findViewById<RelativeLayout>(R.id.rl_edit) val RLDelete = dialog.findViewById<RelativeLayout>(R.id.rl_delete) val RLAdd = dialog.findViewById<RelativeLayout>(R.id.rl_add) RLEdit?.setOnClickListener { //handle click event Toast.makeText(this, "Perform edit operation", Toast.LENGTH_SHORT).show() } RLDelete?.setOnClickListener { //handle click event Toast.makeText(this, "Perform delete operation", Toast.LENGTH_SHORT).show() } RLAdd?.setOnClickListener { //handle click event Toast.makeText(this, "Perform add operation", Toast.LENGTH_SHORT).show() } dialog.show() }
Here, after creating BottomSheetDialog instance:
- set dialog layout using setContentView().
- get dialog views by its id and set click listeners on it.
3 . Run the app, the bottom sheet is displayed at the bottom of the screen.
Modal BottomSheet Example using BottomSheetDialogFragment
1 . Create a subclass of BottomSheetDialogFragment under the root directory, right-click > New > Kotlin File/Class, and name it as BottomSheetFragment.
BottomSheetFragment.kt
package com.c1ctech.androidbottomsheetexp import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Toast import com.google.android.material.bottomsheet.BottomSheetDialogFragment import kotlinx.android.synthetic.main.layout_bottom_sheet_dialog.* class BottomSheetFragment : BottomSheetDialogFragment() { companion object { const val TAG = "CustomBottomSheetDialogFragment" } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { return inflater.inflate(R.layout.layout_bottom_sheet_dialog, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) rl_edit.setOnClickListener { //handle click event Toast.makeText(context, "Perform edit operation", Toast.LENGTH_SHORT).show() } rl_delete.setOnClickListener { //handle click event Toast.makeText(context, "Perform delete operation", Toast.LENGTH_SHORT).show() } rl_add.setOnClickListener { //handle click event Toast.makeText(context, "Perform add operation", Toast.LENGTH_SHORT).show() } } }
Here, we will inflate the layout and handle the button clicks of the inflated layout elements.
2 . In MainActivity, On click of Button (btnBottomSheetDialogFragment ), we will call the DialogFragment show() method which will add the fragment to the fragmentManager and display the dialog.
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) //handle click listener btnBottomSheetDialogFragment.setOnClickListener { showBottomSheetDialogFragment() } } //Display the dialog,adding the fragment to the fragmentManager private fun showBottomSheetDialogFragment() { BottomSheetFragment().show(getSupportFragmentManager(), BottomSheetFragment.TAG); } }