Implement Persistent BottomSheet Dialog in Android with Kotlin/Java

In the previous example we learned about implement Model BottomSheet Dialog in Android, in this chapter we cover how to implement Persistent BottomSheet Dialog. Persistent Bottom Sheet dialogs provide additional content about the current screen. It is as a child of the CoordinatorLayout.

  • Create Sample Project
  • Update Root Element to CoordinatorLayout
  • Create UI for BottomSheetDialog
  • Add Bottom Sheet behavioral to the layout file
  • Include layout inside the MainActivity xml file
  • Add Expand Collapse Animation to BottomSheet
  • Add BottomSheetCallback
  • Enable/Disable BottomSheet Drag feature

 

Let get started

Create Sample Project

Create a Project in Android studio (File->New->New Project) choose Empty Activity template and finish all basic setup Open xml file, you will see default TextView in the file Now drag and drop Text widget from Pallet window.

 

Update Root Element to CoordinatorLayout

Let replace ConstraintLayout file with Coordinator Layout file

Our xml file would be look like this

<?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">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="Persistent BottomSheet Dialog"
        android:textSize="28sp" />
    
</androidx.coordinatorlayout.widget.CoordinatorLayout>

 

Create UI for BottomSheetDialog

So let create a simple layout file

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    android:id="@+id/lnr_bottomsheet"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_height="wrap_content"
    android:background="#F4D595"
    app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"
    app:behavior_hideable="false"
    app:behavior_peekHeight="72dp"
    android:padding="16sp">
    <LinearLayout
        android:layout_width="match_parent"
        android:orientation="horizontal"
        android:gravity="center_vertical"
        android:layout_height="wrap_content">
        <TextView
            android:layout_width="match_parent"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:text="Dr. Rags"
            android:textSize="20sp"
            android:textColor="@color/black"
            android:layout_marginBottom="5dp"
            android:textStyle="bold"

            />
        <ImageView
            android:id="@+id/img_slid"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/arrow_up_24"
            />
    </LinearLayout>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Friday, December 22"
        android:textSize="14sp"
        android:layout_marginBottom="5dp"
        android:textStyle="bold"
        />
    <View
        android:layout_width="match_parent"
        android:layout_height="1dp" android:background="#FFFFFF"/>

    <LinearLayout
        android:id="@+id/lnr_edit"
        android:layout_width="match_parent"
        android:gravity="center_vertical"
        android:layout_marginTop="18dp"
        android:layout_height="wrap_content">
        <ImageView
            android:layout_width="28dp"
            android:layout_height="28dp"
            app:tint="@color/black"
            android:src="@android:drawable/ic_menu_edit"
            />
        <LinearLayout
            android:layout_width="match_parent"
            android:orientation="vertical"
            android:layout_marginLeft="12dp"
            android:layout_height="wrap_content">
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Edit"
                android:textColor="@color/black"
                android:textSize="20sp"
                android:layout_marginBottom="5dp"
                android:textStyle="bold"
                />
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Edit event details"
                android:textSize="14sp"
                android:textColor="#5A503C"
                android:layout_marginBottom="5dp"
                android:textStyle="bold"
                />
        </LinearLayout>

    </LinearLayout>
    <LinearLayout
        android:id="@+id/lnr_pay"
        android:layout_width="match_parent"
        android:gravity="center_vertical"
        android:layout_marginTop="18dp"
        android:layout_height="wrap_content">
        <ImageView
            android:layout_width="28dp"
            android:layout_height="28dp"
            app:tint="@color/black"
            android:src="@android:drawable/stat_notify_more"
            />
        <LinearLayout
            android:layout_width="match_parent"
            android:orientation="vertical"
            android:layout_marginLeft="12dp"
            android:layout_height="wrap_content">
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Payment"
                android:textSize="20sp"
                android:textColor="@color/black"
                android:layout_marginBottom="5dp"
                android:textStyle="bold"
                />
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="add a payment"
                android:textSize="14sp"
                android:textColor="#5A503C"
                android:layout_marginBottom="5dp"
                android:textStyle="bold"
                />
        </LinearLayout>

    </LinearLayout>
    <LinearLayout
        android:id="@+id/lnr_cancel"
        android:layout_width="match_parent"
        android:gravity="center_vertical"
        android:layout_marginTop="18dp"
        android:layout_height="wrap_content">
        <ImageView
            android:layout_width="28dp"
            android:layout_height="28dp"
            app:tint="@color/black"
            android:src="@android:drawable/ic_menu_close_clear_cancel"
            />
        <LinearLayout
            android:layout_width="match_parent"
            android:orientation="vertical"
            android:layout_marginLeft="12dp"
            android:layout_height="wrap_content">
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Cancel"
                android:textSize="20sp"
                android:textColor="@color/black"
                android:layout_marginBottom="5dp"
                android:textStyle="bold"
                />
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Cancel payment"
                android:textSize="14sp"
                android:textColor="#5A503C"
                android:layout_marginBottom="5dp"
                android:textStyle="bold"
                />
        </LinearLayout>

    </LinearLayout>



</LinearLayout>

 

 

Add Bottom Sheet behavioral to the layout file

We have done with our BottomSheet Dialog UI, now lets  add  BottomSheetBehaviour to root element of the layout file to act as Bottomsheet Dialog. 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_height="wrap_content"
    android:background="#F4D595"
    app:behavior_hideable="false"
    app:behavior_peekHeight="72dp"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"
    android:padding="16sp"></LinearLayout>

 

The Bottom Sheet behavioral flags include

  • app:layout_behavior - The class name of a Behavior class defining special runtime behavior for this child view. This applies the BottomSheetBehavior into the XML file. It is the most important BottomSheetBehavior attribute since it defines a given layout as a Bottom Sheet dialog.

  • app:behavior_hideable - takes a Boolean value. If true, a user can drag and hide the dialog by sliding it down. If false, the dialog will float on the screen and will not make it to hidden.

  • app:behavior_peekHeight - it defines the height of the Bottom Sheet visible to the user

Note : To apply BottomSheet Behavior to any layout, it must be a child of CoordinatorLayout

Include layout inside the MainActivity xml file

After including the BottomSheet Behavior layout file to xml, it would be like below

<?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">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="Persistent BottomSheet Dialog"
        android:textSize="28sp" />
    <include layout="@layout/dialog_layout" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

 

Now deploy the application on real device/emulator

Persistent BottomSheet Dialog Android

Add Expand Collapse Animation to BottomSheet

To apply slide up and collapse animations to the Bottomsheet we need to apply several states to it. The Bottom Sheet has several states which we need to understand

  • STATE_EXPANDED - the dialog is visible to its maximum defined height.
  • STATE_COLLAPSED - the dialog is visible depending on the set peekHeight.
  • STATE_DRAGGING - the user is dragging the dialog up and down.
  • STATE_SETTLING - show that the dialog is settling at a specific height. This can be the peekHeight, expanded height, or zero if the dialog is hidden.
  • STATE_HIDDEN - the dialog is not visible.
img_slid.setOnClickListener(View.OnClickListener {
    if (sheetBehavior.state != BottomSheetBehavior.STATE_EXPANDED) {
        sheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED)
    } else {
        sheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED)
    }
})

 

Add BottomSheetCallback

To handle the BottomSheet state we need to implement BottomSheetCallback

val liner_bottomsheet=findViewById<LinearLayout>(R.id.lnr_bottomsheet)
val sheetBehavior = BottomSheetBehavior.from(liner_bottomsheet);
sheetBehavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
    override fun onStateChanged(bottomSheet: View, newState: Int) {
     
    }

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

})

 

Persistent BottomSheet Dialog Android2

Enable/Disable BottomSheet Drag feature

We can enable/disable drag feature of the Bottomsheet by isDraggable property

sheetBehavior.isDraggable=true

Complete code for Persistent Bottomsheet Dialog

MainActivity.kt file

package com.example.persistentbottomsheet

import android.os.Bundle
import android.view.View
import android.widget.ImageView
import android.widget.LinearLayout
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.bottomsheet.BottomSheetBehavior

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val liner_bottomsheet=findViewById<LinearLayout>(R.id.lnr_bottomsheet)
        val img_slid=findViewById<ImageView>(R.id.img_slid)
        val sheetBehavior = BottomSheetBehavior.from(liner_bottomsheet);

        img_slid.setOnClickListener(View.OnClickListener {
            if (sheetBehavior.state != BottomSheetBehavior.STATE_EXPANDED) {
                sheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED)
            } else {
                sheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED)
            }
        })
        sheetBehavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
            override fun onStateChanged(bottomSheet: View, newState: Int) {

            }

            override fun onSlide(bottomSheet: View, slideOffset: Float) {
                img_slid.setRotation(slideOffset * 180);
            }

        })
    }
}

 

activity_main.xml

<?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">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="Persistent BottomSheet Dialog"
        android:textSize="28sp" />
    <include layout="@layout/dialog_layout" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

 

Conclusion:  Android Bottom Sheet dialog is a unique way to display UI content on the current screen. It provides more room to include content.