Android & Kotlin

Bottom Sheet Behavior in Android

Pinterest LinkedIn Tumblr

Welcome Buddy, In this android tutorial, we’ll learn Bottom Sheets Behavior in Android. We’ll see that What is Bottom Sheets Behavior? how it works, and we’ll learn implementation step of Bottom SheetsBehavior. So let’s get started.

What are Bottom Sheets

Bottom Sheets are surface components that hold supplementary content. It mostly anchored bottom of the screen. In simple words, you can say, BottomSheet is a material design component that slides up from bottom of the screen for showing supplementary content.

Usage

Bottom sheets are supplementary surfaces used on mobile. There are two types suitable for different use cases:

Modal bottom sheets – are alternative to inline dialogs on mobile and provide room for descriptions, and iconography. Which open from the bottom on user interaction. If you want to share somethings, option will pop up from bottom something like that. For model bottom sheet I have written a separate article here.

Persistent bottom sheet – provides a collapsed surface that can be expanded by user interaction (dragging, click on some button) access a key feature. In simple words, you say, Persistent Bottom Sheet can slide up and down any time.

Persistent Bottom Sheet

It also knows as BottomSheetBehavior. It works with CoordinatorLayout and displays content on top of the main content. Bottom Sheet is well-written material design component that perfrom enter/exit animations, respond to dragging/swiping gestures, etc.

Implementation step of Persistent BottomSheet

  • Project setup and add material io design dependencies.
  • Prepare the layout of the bottom sheet.
  • Include the bottom sheet with the main content layout.
  • Init the bottom sheet behavior in activity.
  • Test the sample application.

Guys, now I will create a sample application using above step. So let’s get started

1. Project setup and add material io design dependencies

Let’s open the android studio with androidx and add material io dependency

 implementation 'androidx.appcompat:appcompat:1.1.0'
 implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
1.1 Open color.xml file and add below colors
<?xml version="1.0" encoding="utf-8"?>
<resources>
  <color name="colorPrimary">#008577</color>
  <color name="colorPrimaryDark">#00574B</color>
  <color name="colorAccent">#6646ee</color>
  <color name="colorWhite">#fff</color>
</resources>
1.2 Add few dimen file
<?xml version="1.0" encoding="utf-8"?>
<resources>
  <dimen name="default_margin">16dp</dimen>
  <dimen name="drawable_padding">24dp</dimen>
  <dimen name="text_size">16sp</dimen>
  <dimen name="normal_padding">16dp</dimen>
</resources>
1.3 In style.xml add one style for bottom sheet button.
  <style name="bottom_sheet_item">
    <item name="android:textSize">@dimen/text_size</item>
    <item name="android:drawablePadding">@dimen/drawable_padding</item>
    <item name="android:layout_width">0dp</item>
    <item name="android:layout_height">wrap_content</item>
    <item name="android:padding">@dimen/normal_padding</item>
  </style>
2. Prepare the layout of the bottom sheet

In res -> layout folder create an XML layout file named bottom_sheet.xml and paste below code

<?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/bottom_sheet"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#fff"
    android:orientation="vertical"
    app:behavior_hideable="false"
    app:behavior_peekHeight="72dp"
    app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"
    >
  <androidx.constraintlayout.widget.ConstraintLayout
      android:id="@+id/constraintLayout"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:background="@color/colorAccent"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent"
      >

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:layout_marginBottom="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@drawable/user_image"
        />
    <TextView
        android:id="@+id/textView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="8dp"
        android:layout_marginStart="16dp"
        android:layout_marginTop="8dp"
        android:text="Loren Kushwaha"
        android:textColor="@color/colorWhite"
        android:textSize="18sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/imageView"
        app:layout_constraintTop_toTopOf="@+id/imageView"
        />
    <TextView
        android:id="@+id/textView2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="8dp"
        android:layout_marginStart="16dp"
        android:layout_marginTop="2dp"
        android:text="loren.kushwaha@gmail.com"
        android:textColor="@color/colorWhite"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/imageView"
        app:layout_constraintTop_toBottomOf="@+id/textView"
        />
  </androidx.constraintlayout.widget.ConstraintLayout>
  <androidx.appcompat.widget.AppCompatTextView
      android:id="@+id/button"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_marginLeft="8dp"
      android:layout_marginStart="8dp"
      android:drawableTop="@drawable/ic_call"
      android:text="Call"
      android:textColor="@color/colorAccent"
      app:layout_constraintEnd_toStartOf="@+id/button3"
      app:layout_constraintHorizontal_bias="0.5"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="@+id/button3"
      />
  <androidx.appcompat.widget.AppCompatTextView
      android:id="@+id/button2"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_marginEnd="8dp"
      android:layout_marginLeft="8dp"
      android:layout_marginRight="8dp"
      android:layout_marginStart="8dp"
      android:drawableTop="@drawable/ic_save"
      android:text="Save"
      android:textColor="@color/colorAccent"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintHorizontal_bias="0.5"
      app:layout_constraintStart_toEndOf="@+id/button3"
      app:layout_constraintTop_toTopOf="@+id/button3"
      />
  <androidx.appcompat.widget.AppCompatTextView
      android:id="@+id/button3"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_marginLeft="16dp"
      android:layout_marginStart="16dp"
      android:layout_marginTop="24dp"
      android:background="@android:color/transparent"
      android:drawableTop="@drawable/ic_website"
      android:text="Website"
      android:textColor="@color/colorAccent"
      app:layout_constraintEnd_toStartOf="@+id/button2"
      app:layout_constraintHorizontal_bias="0.5"
      app:layout_constraintStart_toEndOf="@+id/button"
      app:layout_constraintTop_toBottomOf="@+id/constraintLayout"
      />
  <View
      android:id="@+id/textView3"
      android:layout_width="0dp"
      android:layout_height="1dp"
      android:layout_marginTop="24dp"
      android:background="#ededed"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/button3"
      />
  <TextView
      android:id="@+id/textView4"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginEnd="8dp"
      android:layout_marginLeft="8dp"
      android:layout_marginRight="8dp"
      android:layout_marginStart="8dp"
      android:layout_marginTop="8dp"
      android:text="We demonstrate android & iOS app development tutorials for Firebase, Camera2 API, Exo Player, Youtube API, Dagger2, RxJava, MVVM, MVP, Realm, and more."
      android:textSize="16sp"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/textView3"
      />
  <View
      android:id="@+id/textView5"
      android:layout_width="0dp"
      android:layout_height="1dp"
      android:layout_marginTop="8dp"
      android:background="#ededed"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/textView4"
      />
  <TextView
      android:id="@+id/textView6"
      android:layout_marginTop="8dp"
      android:text="@string/action_keep"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/textView5"
      style="@style/bottom_sheet_item"

      />
  <TextView
      android:id="@+id/textView7"
      android:text="@string/action_inbox"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/textView6"
      style="@style/bottom_sheet_item"
      />
  <TextView
      android:id="@+id/textView8"
      android:text="@string/action_hangout"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/textView7"
      style="@style/bottom_sheet_item"
      />

</androidx.constraintlayout.widget.ConstraintLayout>

If you saw the above code, I have applied some extra tags such as layout_behavior, behavior_hideable, behavior_peekHeight, etc. don’t worry I will explain each one in details

I have applied the behavior by adding the following xml attribute

app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"

You can set the below behavior flags

  • app:behavior_hideable – its boolean flag, true mean whether bottom sheet can be hidden by dragging.
  • app:behavior_peekHeight –  the peek height for the collapsed state.
  • app:behavior_skipCollapsed –  if the bottom sheet is app:behavior_hideable true, and this is set to true, it does not have a collapsed state.
3. Include the bottom sheet with the main content layout.

So let’s open the resource file where you want to include bottom. BottomSheetBehavior works in just with CoordinatorLayout. That means it should be a direct child of CoordinatorLayout. Open activity layout file and paste below line of code.

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

  <androidx.constraintlayout.widget.ConstraintLayout
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      app:layout_behavior="@string/appbar_scrolling_view_behavior"
      >

    <TextView
        android:id="@+id/textView10"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="This is a sample application of BottomSheet Behaviour Application "
        android:textColor="@color/colorPrimaryDark"
        android:textSize="16sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.054"
        />
    <Button
        android:id="@+id/buttonToggleBottomSheet"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="16dp"
        android:text="Toggle Bottom Sheet"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.497"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textViewState"
        />
    <TextView
        android:id="@+id/textViewState"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="16dp"
        android:textColor="@color/colorAccent"
        android:textSize="16sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView10"
        tools:text="State of BottomSheet Behavior"
        />
  </androidx.constraintlayout.widget.ConstraintLayout>

  <include layout="@layout/bottom_sheet"/>

</androidx.coordinatorlayout.widget.CoordinatorLayout>
4. Init the bottom sheet behavior in Activity.

All design work id has done, let’s move to the real source implementation.

package com.android.bottomsheet;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.constraintlayout.widget.ConstraintLayout;
import com.google.android.material.bottomsheet.BottomSheetBehavior;

public class MainActivity extends AppCompatActivity {

  TextView textViewBottomSheetState;
  Button toggleBottomSheet;
  BottomSheetBehavior bottomSheetBehavior;

  private static final String TAG = "MainActivity";

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    // bind UI
    toggleBottomSheet = findViewById(R.id.buttonToggleBottomSheet);
    textViewBottomSheetState = findViewById(R.id.textViewState);

    // get the bottom sheet view
    ConstraintLayout bottomSheetLayout = findViewById(R.id.bottom_sheet);

    // init the bottom sheet behavior
    bottomSheetBehavior = BottomSheetBehavior.from(bottomSheetLayout);

    // set callback for changes
    bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
      @Override public void onStateChanged(@NonNull View bottomSheet, int newState) {
        switch (newState) {
          case BottomSheetBehavior.STATE_HIDDEN:
            textViewBottomSheetState.setText("STATE HIDDEN");
            break;
          case BottomSheetBehavior.STATE_EXPANDED:
            textViewBottomSheetState.setText("STATE EXPANDED");
            // update toggle button text
            toggleBottomSheet.setText("Expand BottomSheet");
            break;
          case BottomSheetBehavior.STATE_COLLAPSED:
            textViewBottomSheetState.setText("STATE COLLAPSED");
            // update collapsed button text
            toggleBottomSheet.setText("Collapse BottomSheet");
            break;
          case BottomSheetBehavior.STATE_DRAGGING:
            textViewBottomSheetState.setText("STATE DRAGGING");
            break;
          case BottomSheetBehavior.STATE_SETTLING:
            textViewBottomSheetState.setText("STATE SETTLING");
            break;
        }

        Log.d(TAG, "onStateChanged: " + newState);
      }

      @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) {

      }
    });
    // set listener on button click
    toggleBottomSheet.setOnClickListener(new View.OnClickListener() {
      @Override public void onClick(View view) {
        if (bottomSheetBehavior.getState() != BottomSheetBehavior.STATE_EXPANDED) {
          bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
          toggleBottomSheet.setText("Collapse BottomSheet");
        } else {
          bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
          toggleBottomSheet.setText("Expand BottomSheet");
        }
      }
    });
  }
}

In source file mainly we have to initialize BottomSheetBehavior by adding bottom sheet layout. Apart from this, I have set a state change for understanding the current state of the bottom sheet. Remain code is self-explanatory.

State of Bottom Sheet

The Bottom Sheet mainly have 5 states-

  1. STATE_COLLAPSED –  is visible but only showing its peek height. This state is usually the ‘resting position’ of a Bottom Sheet.
  2. STATE_EXPANDED – The bottom sheet is visible and its maximum height and it is neither dragging or settling.
  3. STATE_DRAGGING – User is actively dragging the bottom sheet up or down.
  4. STATE_SETTLING – is settling to a specific height after a drag/swipe gesture.
  5. STATE_HIDDEN – is no longer visible.

Conclusion

In this post, we have learned the implementation of the Bottom Sheet Behavior. I hope it’s helpful for you, then help me by sharing this post with all your friends who learning android app development.

If you have any queries please put your comment below. If you looking to integrate the implementation of any UI/UX in your android project, Feel free to content us

1 Comment

  1. how to crate a bottom sheet display you can show bottom sheet in full screen
    in java and android studio

Write A Comment