Material Design Android Bottom Sheet Tutorial with Example in Kotlin

Android Bottom Sheet is a component that slides up from the bottom to up in an application. 

For example, when you have a video to share and you click on the Share button, it will open a one slider from bottom, which contains available apps in your device.

Sometimes it can also have a menu option. In a simple word, the Android Bottom sheet is an area (surface) that containing extra useful content at the bottom of the screen. It’s hidden in the bottom or partial show to the user will be shown to the user on the action.

In this tutorial, you will learn the following:

  • What is Android Bottom Sheet and it’s type
  • Example and code of Bottom sheet.

Types of Bottom Sheets
There are two types of bottom sheets, Standard Bottom Sheet and Modal Bottom Sheet.

  • Standard bottom sheets:  Display content that complements the screen’s primary content. Remain visible screen users can interact with the primary content. Like, google maps are shown at the bottom how much time and km etc detail of the destination from your point. Here user can interact with both the bottom sheet and the remain of screen content.
  • Modal bottom sheets: This can be an alternative to inline menus or simple dialogs on mobile, providing room for additional items, longer descriptions, and iconography. They must be dismissed in order to interact with the underlying content. Example share the location in Google Maps.
Bottom Sheet behavior and States :
Bottom sheets have 5 states:

  • STATE_COLLAPSED: The bottom sheet is visible but only showing its peek height. This state is usually the ‘resting position’ of a Bottom Sheet
  • STATE_EXPANDED: The bottom sheet is visible and its maximum height and it is neither dragging or settling.
  • STATE_DRAGGING: The user is actively dragging the bottom sheet up or down.
  • 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.

Let’s Build an Example of Android Bottom Sheet

  • res/ layout / bottom_sheet.xml
  • Create “bottom_sheet.xml” and Add code
This will be use for standard bottom sheet (You need to add color, string & drawable files).
<?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"
    android:id="@+id/parent_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <androidx.core.widget.NestedScrollView
            android:id="@+id/nested_scroll_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/grey_3"
            android:scrollbars="none"
            android:scrollingCache="true"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:focusableInTouchMode="true"
                android:orientation="vertical">

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center_vertical"
                    android:paddingLeft="@dimen/spacing_smlarge"
                    android:paddingRight="@dimen/spacing_smlarge"
                    android:text="@string/lorem_ipsum"
                    android:textAppearance="@style/TextAppearance.AppCompat.Subhead"
                    android:textColor="@color/grey_90" />

            </LinearLayout>

        </androidx.core.widget.NestedScrollView>

    </LinearLayout>


    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="@dimen/spacing_large"
        android:clickable="true"
        android:gravity="center"
        android:tint="@color/purple_500"
        app:backgroundTint="@android:color/white"
        app:fabSize="normal"
        app:layout_anchor="@id/bottom_sheet"
        app:layout_anchorGravity="end"
        app:rippleColor="@color/grey_40"
        android:id="@+id/btnCode"
        app:srcCompat="@drawable/baseline_directions_24" />

    <FrameLayout
        android:id="@+id/bottom_sheet"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/white"
        app:behavior_fitToContents="false"
        app:behavior_hideable="false"
        app:behavior_peekHeight="300dp"
        app:behavior_skipCollapsed="true"
        app:layout_behavior="@string/bottom_sheet_behavior">

        <LinearLayout
            android:id="@+id/player_control"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <LinearLayout
                android:id="@+id/lyt_sheet_header"
                android:layout_width="match_parent"
                android:layout_height="80dp"
                android:background="@color/indigo_500"
                android:gravity="center_vertical"
                android:orientation="horizontal"
                android:paddingHorizontal="@dimen/spacing_mlarge">

                <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:orientation="vertical">

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="Starbucks Valencia"
                        android:textAppearance="@style/TextAppearance.AppCompat.Subhead"
                        android:textColor="@android:color/white" />

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="Coffee Shop"
                        android:textAppearance="@style/TextAppearance.AppCompat.Caption"
                        android:textColor="@color/grey_10" />

                </LinearLayout>

                <View
                    android:layout_width="0dp"
                    android:layout_height="0dp"
                    android:layout_weight="1" />

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="@dimen/spacing_large"
                    android:text="15 min"
                    android:textAppearance="@style/TextAppearance.AppCompat.Caption"
                    android:textColor="@color/grey_10" />

            </LinearLayout>

            <LinearLayout
                android:id="@+id/lyt_sheet_header_white"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center_vertical"
                android:orientation="horizontal"
                android:visibility="gone">

                <ImageView
                    android:id="@+id/bt_expand"
                    android:layout_width="?attr/actionBarSize"
                    android:layout_height="?attr/actionBarSize"
                    android:background="?attr/selectableItemBackgroundBorderless"
                    android:clickable="true"
                    android:padding="15dp"
                    app:srcCompat="@drawable/ic_expand_arrow"
                    app:tint="@color/grey_80" />

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Starbucks Valencia"
                    android:textAppearance="@style/TextAppearance.AppCompat.Medium"
                    android:textColor="@color/grey_80" />

            </LinearLayout>

            <View
                android:layout_width="match_parent"
                android:layout_height="1dp"
                android:background="@color/grey_5" />

            <androidx.core.widget.NestedScrollView
                android:layout_width="match_parent"
                android:layout_height="wrap_content">

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical">

                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:gravity="center"
                        android:orientation="vertical"
                        android:paddingHorizontal="?attr/actionBarSize"
                        android:paddingVertical="@dimen/spacing_large">

                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:orientation="horizontal">

                            <LinearLayout
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="?attr/selectableItemBackgroundBorderless"
                                android:clickable="true"
                                android:gravity="center"
                                android:orientation="vertical">

                                <ImageView
                                    android:layout_width="@dimen/spacing_mxlarge"
                                    android:layout_height="@dimen/spacing_mxlarge"
                                    android:background="?attr/selectableItemBackgroundBorderless"
                                    android:clickable="true"
                                    app:srcCompat="@drawable/ic_phone"
                                    app:tint="@color/purple_500" />

                                <TextView
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:layout_marginTop="@dimen/spacing_medium"
                                    android:text="CALL"
                                    android:textAppearance="@style/TextAppearance.AppCompat.Body1"
                                    android:textColor="@color/purple_500"
                                    android:textStyle="bold" />

                            </LinearLayout>

                            <View
                                android:layout_width="0dp"
                                android:layout_height="0dp"
                                android:layout_weight="1" />

                            <LinearLayout
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="?attr/selectableItemBackgroundBorderless"
                                android:clickable="true"
                                android:gravity="center"
                                android:orientation="vertical">

                                <ImageView
                                    android:layout_width="@dimen/spacing_mxlarge"
                                    android:layout_height="@dimen/spacing_mxlarge"
                                    android:background="?attr/selectableItemBackgroundBorderless"
                                    android:clickable="true"
                                    app:srcCompat="@drawable/ic_launch"
                                    app:tint="@color/purple_500" />

                                <TextView
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:layout_marginTop="@dimen/spacing_medium"
                                    android:text="WEBSITE"
                                    android:textAppearance="@style/TextAppearance.AppCompat.Body1"
                                    android:textColor="@color/purple_500"
                                    android:textStyle="bold" />

                            </LinearLayout>

                            <View
                                android:layout_width="0dp"
                                android:layout_height="0dp"
                                android:layout_weight="1" />

                            <LinearLayout
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="?attr/selectableItemBackgroundBorderless"
                                android:clickable="true"
                                android:gravity="center"
                                android:orientation="vertical">

                                <ImageView
                                    android:layout_width="@dimen/spacing_mxlarge"
                                    android:layout_height="@dimen/spacing_mxlarge"
                                    android:background="?attr/selectableItemBackgroundBorderless"
                                    android:clickable="true"
                                    app:srcCompat="@drawable/ic_add_circle_outline"
                                    app:tint="@color/purple_500" />

                                <TextView
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:layout_marginTop="@dimen/spacing_medium"
                                    android:text="SAVE"
                                    android:textAppearance="@style/TextAppearance.AppCompat.Body1"
                                    android:textColor="@color/purple_500"
                                    android:textStyle="bold" />

                            </LinearLayout>

                        </LinearLayout>

                    </LinearLayout>

                    <View
                        android:layout_width="match_parent"
                        android:layout_height="1dp"
                        android:background="@color/grey_5" />

                    <View
                        android:layout_width="match_parent"
                        android:layout_height="@dimen/spacing_middle" />

                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:gravity="center_vertical"
                        android:orientation="horizontal">

                        <ImageView
                            android:layout_width="?attr/actionBarSize"
                            android:layout_height="?attr/actionBarSize"
                            android:padding="15dp"
                            app:srcCompat="@drawable/ic_location"
                            app:tint="@color/purple_500" />

                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="740 Valencia St, San Francisco, CA"
                            android:textAppearance="@style/TextAppearance.AppCompat.Body1"
                            android:textColor="@color/grey_80" />

                    </LinearLayout>

                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:gravity="center_vertical"
                        android:orientation="horizontal">

                        <ImageView
                            android:layout_width="?attr/actionBarSize"
                            android:layout_height="?attr/actionBarSize"
                            android:padding="15dp"
                            app:srcCompat="@drawable/ic_phone"
                            app:tint="@color/purple_500" />

                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="(415) 349-0942"
                            android:textAppearance="@style/TextAppearance.AppCompat.Body1"
                            android:textColor="@color/grey_80" />

                    </LinearLayout>

                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:gravity="center_vertical"
                        android:orientation="horizontal">

                        <ImageView
                            android:layout_width="?attr/actionBarSize"
                            android:layout_height="?attr/actionBarSize"
                            android:padding="15dp"
                            app:srcCompat="@drawable/ic_schedule"
                            app:tint="@color/purple_500" />

                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="Wed, 10 AM - 9 PM"
                            android:textAppearance="@style/TextAppearance.AppCompat.Medium"
                            android:textColor="@color/grey_80" />

                    </LinearLayout>

                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:gravity="center_vertical"
                        android:orientation="horizontal">

                        <ImageView
                            android:layout_width="?attr/actionBarSize"
                            android:layout_height="?attr/actionBarSize"
                            android:padding="15dp"
                            app:srcCompat="@drawable/ic_book"
                            app:tint="@color/purple_500" />

                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="Menu"
                            android:textAppearance="@style/TextAppearance.AppCompat.Body1"
                            android:textColor="@color/grey_80" />

                    </LinearLayout>

                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:gravity="center_vertical"
                        android:orientation="horizontal">

                        <ImageView
                            android:layout_width="?attr/actionBarSize"
                            android:layout_height="?attr/actionBarSize"
                            android:padding="15dp"
                            app:srcCompat="@drawable/ic_label"
                            app:tint="@color/purple_500" />

                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="Add Label"
                            android:textAppearance="@style/TextAppearance.AppCompat.Body1"
                            android:textColor="@color/grey_80" />

                    </LinearLayout>

                    <View
                        android:layout_width="match_parent"
                        android:layout_height="@dimen/spacing_middle" />

                    <View
                        android:layout_width="match_parent"
                        android:layout_height="1dp"
                        android:background="@color/grey_5" />

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="?attr/actionBarSize"
                        android:gravity="center_vertical"
                        android:paddingLeft="@dimen/spacing_smlarge"
                        android:paddingRight="@dimen/spacing_smlarge"
                        android:text="PHOTOS"
                        android:textAppearance="@style/TextAppearance.AppCompat.Medium"
                        android:textColor="@color/grey_80"
                        android:textStyle="bold" />

                    <HorizontalScrollView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginLeft="@dimen/spacing_smlarge"
                        android:layout_marginRight="@dimen/spacing_smlarge"
                        android:scrollbarSize="2dp">

                        <LinearLayout
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:gravity="center_vertical"
                            android:orientation="horizontal">

                            <ImageView
                                android:id="@+id/image_1"
                                android:layout_width="90dp"
                                android:layout_height="90dp"
                                android:layout_marginEnd="@dimen/spacing_medium"
                                android:layout_marginRight="@dimen/spacing_medium"
                                android:scaleType="centerCrop"
                                android:src="@color/grey_20" />

                            <ImageView
                                android:id="@+id/image_2"
                                android:layout_width="90dp"
                                android:layout_height="90dp"
                                android:layout_marginEnd="@dimen/spacing_medium"
                                android:layout_marginRight="@dimen/spacing_medium"
                                android:scaleType="centerCrop"
                                android:src="@color/grey_20" />

                            <ImageView
                                android:id="@+id/image_3"
                                android:layout_width="90dp"
                                android:layout_height="90dp"
                                android:layout_marginEnd="@dimen/spacing_medium"
                                android:layout_marginRight="@dimen/spacing_medium"
                                android:scaleType="centerCrop"
                                android:src="@color/grey_20" />

                            <ImageView
                                android:id="@+id/image_4"
                                android:layout_width="90dp"
                                android:layout_height="90dp"
                                android:layout_marginEnd="@dimen/spacing_medium"
                                android:layout_marginRight="@dimen/spacing_medium"
                                android:scaleType="centerCrop"
                                android:src="@color/grey_20" />

                            <ImageView
                                android:id="@+id/image_5"
                                android:layout_width="90dp"
                                android:layout_height="90dp"
                                android:layout_marginEnd="@dimen/spacing_medium"
                                android:layout_marginRight="@dimen/spacing_medium"
                                android:scaleType="centerCrop"
                                android:src="@color/grey_20" />

                        </LinearLayout>

                    </HorizontalScrollView>

                    <View
                        android:layout_width="match_parent"
                        android:layout_height="@dimen/spacing_middle" />

                    <View
                        android:layout_width="match_parent"
                        android:layout_height="1dp"
                        android:background="@color/grey_5" />

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="?attr/actionBarSize"
                        android:gravity="center_vertical"
                        android:paddingLeft="@dimen/spacing_smlarge"
                        android:paddingRight="@dimen/spacing_smlarge"
                        android:text="DESCRIPTION"
                        android:textAppearance="@style/Base.TextAppearance.AppCompat.Medium"
                        android:textColor="@color/grey_80"
                        android:textStyle="bold" />

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:gravity="center_vertical"
                        android:paddingLeft="@dimen/spacing_smlarge"
                        android:paddingRight="@dimen/spacing_smlarge"
                        android:text="@string/very_long_lorem_ipsum_2"
                        android:textAppearance="@style/TextAppearance.AppCompat.Subhead"
                        android:textColor="@color/grey_90" />

                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:background="@android:color/white"
                        android:orientation="vertical"
                        android:paddingVertical="@dimen/spacing_middle">

                    </LinearLayout>

                </LinearLayout>

            </androidx.core.widget.NestedScrollView>

        </LinearLayout>
    </FrameLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

..
Fragment / BottomSheetFragment.kt
Setting a listener in button and handling behaviour or bottom sheet.
package com.boltuix.bottomsheet

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.boltuix.bottomsheet.databinding.BottomSheetBinding
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback

class BottomSheetFragment : Fragment() {

    private var _binding: BottomSheetBinding? = null

    // This property is only valid between onCreateView and
    // onDestroyView.
    private val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?,
    ): View {

        _binding = BottomSheetBinding.inflate(inflater, container, false)
        return binding.root

    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        //......................................................
        val mBehavior = BottomSheetBehavior.from<View>(binding.bottomSheet)
        mBehavior.addBottomSheetCallback(object : BottomSheetCallback() {
            override fun onStateChanged(bottomSheet: View, newState: Int) {
                if (newState == BottomSheetBehavior.STATE_EXPANDED) {
                    mBehavior.isDraggable = false
                    binding.lytSheetHeader.visibility = View.GONE
                    binding.lytSheetHeaderWhite.visibility = View.VISIBLE
                } else {
                    mBehavior.isDraggable = true
                    binding.lytSheetHeader.visibility = View.VISIBLE
                    binding.lytSheetHeaderWhite.visibility = View.GONE
                }
            }
            override fun onSlide(bottomSheet: View, slideOffset: Float) {}
        })
        binding.btExpand.setOnClickListener(View.OnClickListener {
            mBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED)
        })
        //......................................................
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}
..
..

GET source code on Github:

Comments

  1. Is there an example implementation of this BottomSheet in Jetpack Compose?

    ReplyDelete

Post a Comment