Android BottomSheetBehaviour Tutorial and Examples

Android BottomSheetBehaviour Tutorial and Examples

Android BottomSheetBehavior Examples and Tutorials.

A BottomSheetBehavior is an interaction behavior plugin for a child view of CoordinatorLayout to make it work as a bottom sheet.

BottomSheetBehavior API Definition

BottomSheetBehavior was added in version 23.4.0.

It derives from the Behavior class of CoordinatorLayout.

public class BottomSheetBehavior extends Behavior<V extends View>

Here’s it’s inheritance tree:

java.lang.Object
   ↳    android.support.design.widget.CoordinatorLayout.Behavior<V extends android.view.View>
       ↳    android.support.design.widget.BottomSheetBehavior<V extends android.view.View>

Top BottomSheetBehavior Full Examples

We will look at several examples that make use of or implement BottomSheetBehavior.

These examples will be open source and can be downloaded.

1. Hello World BottomSheet Example

Let’s look at a simple hello world bottomsheet behavior example.
In this example we simply add a View, which can be collapsed:

Collapsed

Here’s the collapsed state:

Hello World BottomSheetBehavior Example

Expanded

Here’s the expanded state:

Hello World BottomSheetBehavior Example Expanded

Let’s start.

(a). Build.gradle

Go ahead and add the required support design library. You can use the later versions.

dependencies {
   compile fileTree(dir: 'libs', include: ['*.jar'])
   testCompile 'junit:junit:4.12'
   compile 'com.android.support:appcompat-v7:23.2.0'
   compile 'com.android.support:design:23.2.0'
}

(a). activity_scrolling.xml

We will have only one layout and one activity. At the root we must have the CoordinatorLayout as our element.

Inside it we will have an AppBarLayout. Inside the AppBarLayout we will have a CollapsingToolbarLayout.

It is inside that CollapsingToolbarLayout where we have ToolBar.

Then we close the AppBarLayout. Then add a simple TextView wrapped inside a FrameLayout. This will be show in our Collapsed state.

Then a LinearLayout with vertical orientation. Here we add more textviews. This will be shown in the expanded state of our BottomSheetBehavior.

So it is this LinearLayout that you can of in this case as our BottomSheet, take note of the id we are assigning it.

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout

   android_layout_width="match_parent"
   android_layout_height="match_parent"
   android_fitsSystemWindows="true"
   tools_context="sample.com.bottomsheet.ScrollingActivity">

   <android.support.design.widget.AppBarLayout
      android_id="@+id/app_bar"
      android_layout_width="match_parent"
      android_layout_height="@dimen/app_bar_height"
      android_fitsSystemWindows="true"
      android_theme="@style/AppTheme.AppBarOverlay">

      <android.support.design.widget.CollapsingToolbarLayout
         android_id="@+id/toolbar_layout"
         android_layout_width="match_parent"
         android_layout_height="match_parent"
         android_fitsSystemWindows="true"
         app_contentScrim="?attr/colorPrimary"
         app_layout_scrollFlags="scroll|exitUntilCollapsed">

         <android.support.v7.widget.Toolbar
            android_id="@+id/toolbar"
            android_layout_width="match_parent"
            android_layout_height="?attr/actionBarSize"
            app_layout_collapseMode="pin"
            app_popupTheme="@style/AppTheme.PopupOverlay" />

      </android.support.design.widget.CollapsingToolbarLayout>
   </android.support.design.widget.AppBarLayout>

   <FrameLayout

      android_layout_width="match_parent"
      android_layout_height="match_parent"
      android_background="@android:color/holo_red_light">

      <TextView
         android_layout_width="wrap_content"
         android_layout_height="wrap_content"
         android_layout_gravity="center"
         android_text="Main Content"
         android_textAppearance="@style/TextAppearance.AppCompat.Title" />

   </FrameLayout>

   <LinearLayout
      android_id="@+id/design_bottom_sheet"
      android_layout_width="match_parent"
      android_layout_height="wrap_content"
      android_background="@android:color/holo_green_light"
      android_orientation="vertical"
      android_paddingTop="8dp"
      app_behavior_peekHeight="32dp"
      app_layout_behavior="android.support.design.widget.BottomSheetBehavior">

      <TextView
         android_layout_width="match_parent"
         android_layout_height="wrap_content"
         android_layout_marginBottom="8dp"
         android_text="Line 1" />

      <TextView
         android_layout_width="match_parent"
         android_layout_height="wrap_content"
         android_layout_marginBottom="8dp"
         android_text="Line 2" />

      <TextView
         android_layout_width="match_parent"
         android_layout_height="wrap_content"
         android_layout_marginBottom="8dp"
         android_text="Line 3" />

      <TextView
         android_layout_width="match_parent"
         android_layout_height="wrap_content"
         android_layout_marginBottom="8dp"
         android_text="Line 4" />

      <TextView
         android_layout_width="match_parent"
         android_layout_height="wrap_content"
         android_layout_marginBottom="8dp"
         android_text="Line 5" />

      <TextView
         android_layout_width="match_parent"
         android_layout_height="wrap_content"
         android_layout_marginBottom="8dp"
         android_text="Line 6" />

   </LinearLayout>

</android.support.design.widget.CoordinatorLayout>

(c). ScrollingActivity.java

Create an Activity if it hasn’t been created by android studio already.

It is our only activity and yours maybe already named MainActivity, no problem.

public class ScrollingActivity extends AppCompatActivity {..}

Inside our onCreate() we will be referencing our BottomSheet:

 View bottomSheet = findViewById(R.id.design_bottom_sheet);

This will reference that LinearLayout which will be acting as our bottom sheet.

Then we initialize the BottomSheetBehavior for our BottomSheet:

BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);

Then we can override the BottomSheetCallBacks:

    behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
         @Override
         public void onSlide(@NonNull View bottomSheet, float slideOffset) {
            // React to dragging events
            Log.d(TAG, "onSlide: " + slideOffset);
         }

         @Override
         public void onStateChanged(@NonNull View bottomSheet, int newState) {
            Log.d(TAG, "onStateChanged: " + newState);
            // React to state change
         }
      });

Here’s the full code:

package sample.com.bottomsheet;

import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomSheetBehavior;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;

public class ScrollingActivity extends AppCompatActivity {

   private static final String TAG = ScrollingActivity.class.getSimpleName();

   @Override
   public boolean onCreateOptionsMenu(Menu menu) {
      // Inflate the menu; this adds items to the action bar if it is present.
      getMenuInflater().inflate(R.menu.menu_scrolling, menu);
      return true;
   }

   @Override
   public boolean onOptionsItemSelected(MenuItem item) {
      // Handle action bar item clicks here. The action bar will
      // automatically handle clicks on the Home/Up button, so long
      // as you specify a parent activity in AndroidManifest.xml.
      int id = item.getItemId();

      //noinspection SimplifiableIfStatement
      if (id == R.id.action_settings) {
         return true;
      }
      return super.onOptionsItemSelected(item);
   }

   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_scrolling);
      Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
      setSupportActionBar(toolbar);

      View bottomSheet = findViewById(R.id.design_bottom_sheet);
      BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);
      behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
         @Override
         public void onSlide(@NonNull View bottomSheet, float slideOffset) {
            // React to dragging events
            Log.d(TAG, "onSlide: " + slideOffset);
         }

         @Override
         public void onStateChanged(@NonNull View bottomSheet, int newState) {
            Log.d(TAG, "onStateChanged: " + newState);
            // React to state change
         }
      });
   }
}

(d). How to Run.

We only have one class and one layout in the project. You can copy them or download the full project from here:

No. Resource Action
1. GitHub Browse/Download
2. Project Thanks to @Plinzen

Android GoogleMap-Like BottomSheetBehavior

In this class we will look at yet another BottomSheetBehavior implementation.

We learn from and re-create an open source example of BottomSheetBehavior mimicking Google Map Behavior created by @miguelhincapie.

It makes use of a library called CustomBottomSheetBehavior and is maintained by @miguelhincapie.

Demo

Here’s the project demo.

Android CustomBottomSheetBehavior

1. Installation

We start by installing the library as it is third party. We can easily do this via android studio through the gradle build system.

So proceed over to app level build.gradle and add the following under the dependencies closure:

implementation 'com.mahc.custombottomsheetbehavior:googlemaps-like:0.9.1'

Sync your project after that.

2. Create User Interface

Well we will have three layouts.

(a). activity_main.xml

In our activity_main.xml we will have a CoordinatorLayout.
Inside it we include a FrameLayout, a placeholder that can show our dummy map.

Our ToolBar will be placed in our AppBarLayout.

Then followed by a ViewPager for our pages.

We will then have our NestedScrollView, with our BottomSheet content placed inside it.

We then have a FloatingActionButton and lastly a custombottomsheetbehavior.

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    android_id="@+id/coordinatorlayout"

    android_layout_width="match_parent"
    android_layout_height="match_parent"
    android_fitsSystemWindows="true"
    tools_context="com.mahc.custombottomsheet.MainActivity">

    <FrameLayout
        android_id="@+id/dummy_framelayout_replacing_map"
        android_layout_width="match_parent"
        android_layout_height="match_parent"
        android_background="@android:color/darker_gray"
        android_fitsSystemWindows="true"/>
    <!--</FrameLayout>-->
    <!--<fragment-->
    <!--android:layout_width="match_parent"-->
    <!--android:layout_height="match_parent"-->
    <!--android:id="@+id/support_map"-->
    <!--android:name="com.google.android.gms.maps.SupportMapFragment"/>-->

    <android.support.design.widget.AppBarLayout
        android_id="@+id/appbarlayout"
        android_layout_width="match_parent"
        android_layout_height="wrap_content"
        android_theme="@style/AppTheme.AppBarOverlay"
        app_layout_behavior="@string/ScrollingAppBarLayoutBehavior">

        <android.support.v7.widget.Toolbar
            android_id="@+id/toolbar"
            android_layout_width="match_parent"
            android_layout_height="?attr/actionBarSize"
            app_popupTheme="@style/AppTheme.PopupOverlay"/>
    </android.support.design.widget.AppBarLayout>

    <android.support.v4.view.ViewPager
        android_id="@+id/pager"
        android_layout_width="match_parent"
        android_layout_height="@dimen/anchor_point"
        android_background="@color/colorAccent"
        app_layout_behavior="@string/BackDropBottomSheetBehavior"
        android_fitsSystemWindows="true">
    </android.support.v4.view.ViewPager>

    <android.support.v4.widget.NestedScrollView
        android_layout_width="match_parent"
        android_layout_height="match_parent"
        android_orientation="vertical"
        app_behavior_peekHeight="@dimen/bottom_sheet_peek_height"
        android_id="@+id/bottom_sheet"
        app_layout_behavior="@string/BottomSheetBehaviorGoogleMapsLike"
        app_anchorPoint="@dimen/anchor_point"
        app_behavior_hideable="true"
        android_fitsSystemWindows="true">

        <include
            layout="@layout/bottom_sheet_content"
            android_layout_width="match_parent"
            android_layout_height="match_parent"
            android_fitsSystemWindows="true"/>
    </android.support.v4.widget.NestedScrollView>

    <android.support.design.widget.FloatingActionButton
        android_layout_height="wrap_content"
        android_layout_width="wrap_content"
        app_layout_anchor="@id/bottom_sheet"
        app_layout_anchorGravity="top|right|end"
        android_src="@drawable/ic_action_go"
        android_layout_margin="@dimen/fab_margin"
        app_layout_behavior="@string/ScrollAwareFABBehavior"
        android_clickable="true"
        android_focusable="true"/>

    <com.mahc.custombottomsheetbehavior.MergedAppBarLayout
        android_id="@+id/mergedappbarlayout"
        android_layout_width="match_parent"
        android_layout_height="wrap_content"
        app_layout_behavior="@string/MergedAppBarLayoutBehavior"/>

</android.support.design.widget.CoordinatorLayout>
(b). bottom_sheet_content.xml

Next we have the bottom_sheet_content layout. At the root we have a LinearLayout.

This layout will be displaying our content which will be rendered in TextViews and ImageViews,so we add those widgets as well as ImageButton.

Here are the xml widgets we make use of in this layout.

  1. TextView.
  2. ImageView.
  3. Button.
  4. ImageButton

as well as Viewgroups like:

  1. LinearLayout.
  2. RelativeLayout.
  3. FrameLayout.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout

    android_layout_width="match_parent"
    android_layout_height="match_parent"
    android_orientation="vertical"
    android_paddingBottom="16dp"
    android_background="@android:color/white">

    <RelativeLayout
        android_layout_width="match_parent"
        android_layout_height="@dimen/bottom_sheet_peek_height"
        android_background="@color/colorPrimary"
        android_paddingTop="8dp"
        android_paddingStart="16dp"
        android_paddingEnd="16dp"
        android_paddingBottom="8dp">

        <LinearLayout
            android_layout_width="wrap_content"
            android_layout_height="match_parent"
            android_orientation="vertical">

            <TextView
                android_id="@+id/bottom_sheet_title"
                android_layout_width="wrap_content"
                android_layout_height="wrap_content"
                android_text="Title dummy"
                android_textColor="@android:color/white"
                android_textSize="19sp"/>

            <TextView
                android_id="@+id/text_dummy1"
                android_layout_width="wrap_content"
                android_layout_height="wrap_content"
                android_text="Text dummy 1234 1234"
                android_textColor="@android:color/white"
                android_textSize="12sp"
                android_layout_marginTop="5dp"/>

            <TextView
                android_layout_width="wrap_content"
                android_layout_height="wrap_content"
                android_text="Text dummy qwer asdf zxcv"
                android_textColor="@android:color/white"
                android_textSize="12sp"
                android_layout_marginTop="5dp"/>

        </LinearLayout>

        <TextView
            android_layout_width="wrap_content"
            android_layout_height="wrap_content"
            android_text="5 min"
            android_textColor="@android:color/white"
            android_textSize="14sp"
            android_layout_alignParentEnd="true"
            android_layout_centerVertical="true"
            android_paddingTop="8dp"/>

    </RelativeLayout>

    <LinearLayout
        android_layout_width="match_parent"
        android_layout_height="wrap_content"
        android_orientation="horizontal"
        android_gravity="center_horizontal"
        android_paddingStart="16dp"
        android_paddingEnd="16dp"
        android_paddingBottom="12dp"
        android_background="@drawable/border_bottom">

        <RelativeLayout
            android_layout_width="wrap_content"
            android_layout_height="match_parent">

            <ImageButton
                android_id="@+id/button1"
                android_layout_width="70dp"
                android_layout_height="60dp"
                android_src="@android:drawable/ic_dialog_map"
                android_layout_centerHorizontal="true"
                android_background="?attr/selectableItemBackgroundBorderless"/>

            <TextView
                android_layout_width="wrap_content"
                android_layout_height="wrap_content"
                android_text="BUTTON 1"
                android_textColor="@android:color/black"
                android_layout_alignParentBottom="true"/>
        </RelativeLayout>

        <LinearLayout
            android_id="@+id/establecimiento_layout_favoritos_button"
            android_layout_width="wrap_content"
            android_layout_height="wrap_content"
            android_orientation="vertical"
            android_layout_marginEnd="20dp"
            android_layout_marginStart="20dp">

            <ImageButton
                android_id="@+id/button2"
                android_layout_width="70dp"
                android_layout_height="60dp"
                android_src="@android:drawable/ic_dialog_info"
                android_layout_centerHorizontal="true"
                android_background="?attr/selectableItemBackgroundBorderless"/>

            <TextView
                android_layout_width="wrap_content"
                android_layout_height="wrap_content"
                android_text="BUTTON 2"
                android_textColor="@android:color/black"/>
        </LinearLayout>

        <RelativeLayout
            android_layout_width="wrap_content"
            android_layout_height="match_parent">

            <ImageButton
                android_id="@+id/establecimiento_share_button"
                android_layout_width="70dp"
                android_layout_height="60dp"
                android_src="@android:drawable/ic_menu_share"
                android_layout_centerHorizontal="true"
                android_background="?attr/selectableItemBackgroundBorderless"/>

            <TextView
                android_layout_width="wrap_content"
                android_layout_height="wrap_content"
                android_text="BUTTON 3"
                android_textColor="@android:color/black"
                android_layout_alignParentBottom="true"/>
        </RelativeLayout>
    </LinearLayout>

    <RelativeLayout
        android_layout_width="match_parent"
        android_layout_height="wrap_content"
        android_background="@drawable/border_bottom">

        <ImageView
            android_id="@+id/establecimiento_icon_sucursales"
            android_layout_width="wrap_content"
            android_layout_height="wrap_content"
            app_srcCompat="@android:drawable/ic_secure"
            android_layout_marginEnd="16dp"
            android_layout_marginTop="12dp"
            android_layout_marginStart="16dp"
            android_layout_alignParentStart="true"
            android_layout_alignParentTop="true"/>

        <LinearLayout
            android_layout_width="match_parent"
            android_layout_height="wrap_content"
            android_orientation="vertical"
            android_layout_toEndOf="@id/establecimiento_icon_sucursales"
            android_layout_marginStart="16dp"
            android_layout_marginEnd="16dp">

            <FrameLayout
                android_layout_width="match_parent"
                android_layout_height="48dp">

                <Button
                    android_id="@+id/establecimiento_sucursal_row_button"
                    android_layout_width="wrap_content"
                    android_layout_height="wrap_content"
                    android_text="Text dummy 1"
                    android_layout_gravity="center_vertical"
                    android_background="?attr/selectableItemBackgroundBorderless"
                    android_textAllCaps="false"
                    android_textColor="@android:color/black"/>
            </FrameLayout>

            <FrameLayout
                android_layout_width="match_parent"
                android_layout_height="48dp">

                <Button
                    android_layout_width="wrap_content"
                    android_layout_height="wrap_content"
                    android_text="Text dummy 2"
                    android_layout_gravity="center_vertical"
                    android_background="?attr/selectableItemBackgroundBorderless"
                    android_textAllCaps="false"
                    android_textColor="@android:color/black"/>
            </FrameLayout>

            <FrameLayout
                android_layout_width="match_parent"
                android_layout_height="48dp">

                <Button
                    android_layout_width="wrap_content"
                    android_layout_height="wrap_content"
                    android_text="Text dummy 3"
                    android_layout_gravity="center_vertical"
                    android_background="?attr/selectableItemBackgroundBorderless"
                    android_textAllCaps="false"
                    android_textColor="@android:color/black"/>
            </FrameLayout>

        </LinearLayout>

    </RelativeLayout>

    <FrameLayout
        android_layout_width="match_parent"
        android_layout_height="56dp"
        android_layout_marginStart="16dp"
        android_layout_marginEnd="16dp">

        <TextView
            android_layout_width="wrap_content"
            android_layout_height="wrap_content"
            android_text="APACHE LICENSE"
            android_layout_gravity="center_vertical"
            android_textSize="18sp"
            android_textColor="@android:color/darker_gray"/>
    </FrameLayout>

    <TextView
        android_layout_width="wrap_content"
        android_layout_height="wrap_content"
        android_layout_margin="16dp"

        android_text="@string/dummy_text"
        android_textSize="12sp"
        android_textColor="@android:color/black"/>

    <FrameLayout
        android_layout_width="match_parent"
        android_layout_height="620dp"
        android_background="@color/colorAccent"
        android_layout_marginTop="40dp">

        <TextView
            android_layout_width="wrap_content"
            android_layout_height="wrap_content"
            android_layout_gravity="center"
            android_text="Your remaining content here"
            android_textColor="@android:color/white" />

    </FrameLayout>
</LinearLayout>
(c). pager_item.xml

Then the pager_item.xml.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    android_orientation="vertical" android_layout_width="match_parent"
    android_layout_height="match_parent">
    <ImageView
        android_layout_width="match_parent"
        android_layout_height="match_parent"
        android_id="@+id/imageView"
        android_scaleType="centerCrop"/>
</LinearLayout>

Our Java Code

(a). ItemPagerAdapter.java

First create a new class. Call it a ItemPagerAdapter and let’s make it derive from android.support.v4.view.PagerAdapter.

public class ItemPagerAdapter extends android.support.v4.view.PagerAdapter {..}

PagerAdapter acts as the base class for providing the adapter to populate pages inside of that ViewPager.

Add three instance fields in our class:

    Context mContext;
    LayoutInflater mLayoutInflater;
    final int[] mItems;

First the Context is an interface to global information about an application environment. Normally Context allows access to application-specific resources and classes, as well as up-calls for application-level operations such as launching activities, broadcasting and receiving intents, etc.

In this case it will allow us inflate our layout into a view.

Then we have a LayoutInflater, a class that allows us instantiates a layout XML file into its corresponding View objects.

The int array will hold us image ids.

Then our constructor is responsible for first receiving a context object which will be required during inflation of our pager_item layout and secondly the int items which will hold our image ids.

We will also perform the inflation inside that constructor.

    public ItemPagerAdapter(Context context, int[] items) {
        this.mContext = context;
        this.mLayoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        this.mItems = items;
    }

We then override the other methods.

Here’s the full code for this class:

package com.mahc.custombottomsheet;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;

import com.mahc.custombottomsheet.R;

public class ItemPagerAdapter extends android.support.v4.view.PagerAdapter {

    Context mContext;
    LayoutInflater mLayoutInflater;
    final int[] mItems;

    public ItemPagerAdapter(Context context, int[] items) {
        this.mContext = context;
        this.mLayoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        this.mItems = items;
    }

    @Override
    public int getCount() {
        return mItems.length;
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == ((LinearLayout) object);
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        View itemView = mLayoutInflater.inflate(R.layout.pager_item, container, false);
        ImageView imageView = (ImageView) itemView.findViewById(R.id.imageView);
        imageView.setImageResource(mItems[position]);
        container.addView(itemView);
        return itemView;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((LinearLayout) object);
    }
}
(b). MainActivity.java

Finally here’s our main activity. Maybe it’s been generate to you by android studio.

So go ahead and as instance fields add an int array to hold our Drawables.

Also we’ll have a TextView:

    int[] mDrawables = {
            R.drawable.cheese_3,
            R.drawable.cheese_3,
            R.drawable.cheese_3,
            R.drawable.cheese_3,
            R.drawable.cheese_3,
            R.drawable.cheese_3
    };

    TextView bottomSheetTextView;

We start by referencing our widgets CoordinatorLayout as well as View to represent the bottom sheet.

        CoordinatorLayout coordinatorLayout = (CoordinatorLayout) findViewById(R.id.coordinatorlayout);
        View bottomSheet = coordinatorLayout.findViewById(R.id.bottom_sheet);

Then we reference the BottomSheetBehaviorGoogleMapsLike. This is the library we are using to create a bottom sheet behavior like that in Google maps.

        final BottomSheetBehaviorGoogleMapsLike behavior = BottomSheetBehaviorGoogleMapsLike.from(bottomSheet);

Then listen to various callbacks:

        behavior.addBottomSheetCallback(new BottomSheetBehaviorGoogleMapsLike.BottomSheetCallback() {
            @Override
            public void onStateChanged(@NonNull View bottomSheet, int newState) {

                }
            }

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

We are interested especially in the state change event where we get various state of our BottomSheetBehaviorGoogleMapsLike.

Here’s the code:

package com.mahc.custombottomsheet;

import android.support.annotation.NonNull;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CoordinatorLayout;
import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import com.mahc.custombottomsheetbehavior.BottomSheetBehaviorGoogleMapsLike;
import com.mahc.custombottomsheetbehavior.MergedAppBarLayout;
import com.mahc.custombottomsheetbehavior.MergedAppBarLayoutBehavior;

public class MainActivity extends AppCompatActivity {

    int[] mDrawables = {
            R.drawable.cheese_3,
            R.drawable.cheese_3,
            R.drawable.cheese_3,
            R.drawable.cheese_3,
            R.drawable.cheese_3,
            R.drawable.cheese_3
    };

    TextView bottomSheetTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.setDisplayHomeAsUpEnabled(true);
            actionBar.setTitle(" ");
        }

        /**
         * If we want to listen for states callback
         */
        CoordinatorLayout coordinatorLayout = (CoordinatorLayout) findViewById(R.id.coordinatorlayout);
        View bottomSheet = coordinatorLayout.findViewById(R.id.bottom_sheet);
        final BottomSheetBehaviorGoogleMapsLike behavior = BottomSheetBehaviorGoogleMapsLike.from(bottomSheet);
        behavior.addBottomSheetCallback(new BottomSheetBehaviorGoogleMapsLike.BottomSheetCallback() {
            @Override
            public void onStateChanged(@NonNull View bottomSheet, int newState) {
                switch (newState) {
                    case BottomSheetBehaviorGoogleMapsLike.STATE_COLLAPSED:
                        Log.d("bottomsheet-", "STATE_COLLAPSED");
                        break;
                    case BottomSheetBehaviorGoogleMapsLike.STATE_DRAGGING:
                        Log.d("bottomsheet-", "STATE_DRAGGING");
                        break;
                    case BottomSheetBehaviorGoogleMapsLike.STATE_EXPANDED:
                        Log.d("bottomsheet-", "STATE_EXPANDED");
                        break;
                    case BottomSheetBehaviorGoogleMapsLike.STATE_ANCHOR_POINT:
                        Log.d("bottomsheet-", "STATE_ANCHOR_POINT");
                        break;
                    case BottomSheetBehaviorGoogleMapsLike.STATE_HIDDEN:
                        Log.d("bottomsheet-", "STATE_HIDDEN");
                        break;
                    default:
                        Log.d("bottomsheet-", "STATE_SETTLING");
                        break;
                }
            }

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

        MergedAppBarLayout mergedAppBarLayout = findViewById(R.id.mergedappbarlayout);
        MergedAppBarLayoutBehavior mergedAppBarLayoutBehavior = MergedAppBarLayoutBehavior.from(mergedAppBarLayout);
        mergedAppBarLayoutBehavior.setToolbarTitle("Title Dummy");
        mergedAppBarLayoutBehavior.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                behavior.setState(BottomSheetBehaviorGoogleMapsLike.STATE_ANCHOR_POINT);
            }
        });

        bottomSheetTextView = (TextView) bottomSheet.findViewById(R.id.bottom_sheet_title);
        ItemPagerAdapter adapter = new ItemPagerAdapter(this,mDrawables);
        ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
        viewPager.setAdapter(adapter);

        behavior.setState(BottomSheetBehaviorGoogleMapsLike.STATE_ANCHOR_POINT);
        //behavior.setCollapsible(false);
    }
}
(d). How to Run.

The download contains both a library as well as code. Just go to the app folder and you find the code for the sample.

Go over to your app level build.gradle and add statement via the implementation statement just as we did in the Installation section.

No. Resource Action
1. GitHub Download
2. GitHub Browse
3. Project Thanks to @miguelhincapie

AnchorSheetBehaviour

This is a project that adds anchor state to the android BottomSheetBehavior.

AnchorBottomSheetBehavior extends the Android’s behavior BottomSheetBehavior by adding the following:

  1. STATE_ANCHOR: push the bottom sheet to an anchor state defined by Anchor offset
  2. STATE_FORCE_HIDE: force the bottom sheet to hide regardless of hideable flag

Here’s the demo for this project:

Android AnchorBottomSheetBehavior

Installation

We are using a third party library so we start by adding an implementation statement to fetch for us the library.

First we go to the root level build.gradle and add jitpack maven repository under the repositories closure as follows:

allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}

Then we navigate to the app level build.gradle and add the following under the dependencies:

implementation 'com.github.skimarxall:AnchorSheetBehavior:master-SNAPSHOT'

XML Layouts

(a). activity_main.xml

As expected we have CoordinatorLayout defined at the root of xml layout.

Then we have a clickable TextView which when clicked will toggle the state of our AnchorSheetBehavior.

We will use a FrameLayout as our anchor panel. Inside we will have a textView to contain our content.

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout

    android_layout_width="match_parent"
    android_layout_height="match_parent">

    <TextView
        android_layout_width="match_parent"
        android_layout_height="match_parent"
        android_layout_margin="30dp"
        android_gravity="center_horizontal"
        android_onClick="onTap"
        android_text="Tap me!"
        android_textSize="25sp" />

    <FrameLayout
        android_id="@+id/anchor_panel"
        android_layout_width="match_parent"
        android_layout_height="match_parent"
        android_background="@color/colorPrimaryDark"
        app_layout_behavior="com.hardsoftstudio.widget.AnchorSheetBehavior"
        app_behavior_peekHeight="@dimen/panel_content_height">

        <TextView
            android_id="@+id/panel_content"
            android_layout_width="match_parent"
            android_layout_height="@dimen/panel_content_height"
            android_gravity="center"
            android_textColor="@android:color/white"
            android_text="@string/slide_me_up"
            android_textSize="20sp" />

    </FrameLayout>

</android.support.design.widget.CoordinatorLayout>

Java Code

(a). MainActivity.java

We start by declaring our AnchorBottomSheetBehavior and TextView which will hold our data.

Remember we had a clickable textview defined in our layout. When clicked the following method will get invoked:

    public void onTap(View view) {
        switch (anchorBehavior.getState()) {
            case AnchorSheetBehavior.STATE_ANCHOR:
                anchorBehavior.setState(AnchorSheetBehavior.STATE_EXPANDED);
                break;
            case AnchorSheetBehavior.STATE_COLLAPSED:
                anchorBehavior.setState(AnchorSheetBehavior.STATE_ANCHOR);
                break;
            case AnchorSheetBehavior.STATE_HIDDEN:
                anchorBehavior.setState(AnchorSheetBehavior.STATE_COLLAPSED);
                break;
            case AnchorSheetBehavior.STATE_EXPANDED:
                anchorBehavior.setState(AnchorSheetBehavior.STATE_ANCHOR);
                break;
            default:
                break;
        }
    }

There you can see we have used a switch statement to switch through the various AnchorSheetBehavior states, setting the appropriate states in the process.

Here’s the full code:

package com.hardsoftstudio.anchorbottomsheet;

import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;

import com.hardsoftstudio.widget.AnchorSheetBehavior;

public class MainActivity extends AppCompatActivity {

    private AnchorSheetBehavior<View> anchorBehavior;
    private TextView content;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        content = findViewById(R.id.panel_content);

        anchorBehavior = AnchorSheetBehavior.from(findViewById(R.id.anchor_panel));
        anchorBehavior.setHideable(true);
        anchorBehavior.setState(AnchorSheetBehavior.STATE_HIDDEN);
        anchorBehavior.setAnchorSheetCallback(new AnchorSheetBehavior.AnchorSheetCallback() {
            @Override
            public void onStateChanged(@NonNull View bottomSheet, @AnchorSheetBehavior.State int newState) {
                content.setText(newState == AnchorSheetBehavior.STATE_EXPANDED ? R.string.slide_me_down : R.string.slide_me_up);
            }

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

            }
        });
    }

    @Override
    public void onBackPressed() {
        int state = anchorBehavior.getState();
        if (state == AnchorSheetBehavior.STATE_COLLAPSED || state == AnchorSheetBehavior.STATE_HIDDEN) {
            super.onBackPressed();
        } else {
            anchorBehavior.setState(AnchorSheetBehavior.STATE_COLLAPSED);
        }
    }

    public void onTap(View view) {
        switch (anchorBehavior.getState()) {
            case AnchorSheetBehavior.STATE_ANCHOR:
                anchorBehavior.setState(AnchorSheetBehavior.STATE_EXPANDED);
                break;
            case AnchorSheetBehavior.STATE_COLLAPSED:
                anchorBehavior.setState(AnchorSheetBehavior.STATE_ANCHOR);
                break;
            case AnchorSheetBehavior.STATE_HIDDEN:
                anchorBehavior.setState(AnchorSheetBehavior.STATE_COLLAPSED);
                break;
            case AnchorSheetBehavior.STATE_EXPANDED:
                anchorBehavior.setState(AnchorSheetBehavior.STATE_ANCHOR);
                break;
            default:
                break;
        }
    }
}

How to Download and Run

First download the project below.

The download contains both a library as well as code. Just go to the app folder and you find the code for the sample.

Go over to your app level build.gradle and add our implementation statement just as we did in the Installation section.

No. Resource Action
1. GitHub Download
2. GitHub Browse
3. Credit @miguelhincapie

BEFORE YOU GO

YOU'VE BEEN SELECTED FOR A GIFT

Thanks for stopping by. My name is Oclemy(Clement Ochieng) and we have selected you as a recipient of a GIFT you may like ! Together with Skillshare we are offering you PROJECTS and 1000s of PREMIUM COURSES at Skillshare for FREE for 1 MONTH. To be eligible all you need is by sign up right now using my profile .

Related Examples

Leave a Reply

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

*

code