Modal Bottom Sheet with Material Design in Android

    In the previous post, I have introduced the way to make a bottom sheet with new updated feature in Design Support Library 23.2.0. But, there is a more popular style called Modal bottom sheet, which you can see in a lot of apps like Google Drive:
    When it show, the main UI will be blurred and you can drag to change it's state or click at the main screen to dismiss it.
    Through this small tip, I will present the way to create a modal bottom sheet by using   BottomSheetDialogFragment with a simple custom layout. Hope it can helpful with your work!

Create a custom bottom sheet layout

    If you would like to declaring a bottom sheet with an your own layout (in xml file), you must make a subclass of BottomSheetDialogFragment. By overriding setupDialog() method, the custom layout will be inflated to the bottom sheet frame. Moreover, the it's sliding or state changing event will be handle by a BottomSheetBehavior.BottomSheetCallback variable. Full code for this "custom bottom sheet":
CustomBottomSheetDialogFragment.java
package info.devexchanges.modalbottomsheet;

import android.app.Dialog;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.BottomSheetBehavior;
import android.support.design.widget.BottomSheetDialogFragment;
import android.support.design.widget.CoordinatorLayout;
import android.view.View;

public class CustomBottomSheetDialogFragment extends BottomSheetDialogFragment {


    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    private BottomSheetBehavior.BottomSheetCallback mBottomSheetBehaviorCallback = new BottomSheetBehavior.BottomSheetCallback() {

        @Override
        public void onStateChanged(@NonNull View bottomSheet, int newState) {
            if (newState == BottomSheetBehavior.STATE_HIDDEN) {
                dismiss();
            }
        }

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

    @Override
    public void setupDialog(Dialog dialog, int style) {
        super.setupDialog(dialog, style);
        View contentView = View.inflate(getContext(), R.layout.dialog_modal, null);
        dialog.setContentView(contentView);
        CoordinatorLayout.LayoutParams layoutParams =
                (CoordinatorLayout.LayoutParams) ((View) contentView.getParent()).getLayoutParams();
        CoordinatorLayout.Behavior behavior = layoutParams.getBehavior();
        if (behavior != null && behavior instanceof BottomSheetBehavior) {
            ((BottomSheetBehavior) behavior).setBottomSheetCallback(mBottomSheetBehaviorCallback);
        }
    }
}
    And this is it's layout:
dialog_modal.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

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

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:drawableTop="@drawable/download"
            android:gravity="center"
            android:text="Download"
            android:textColor="@android:color/black" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:drawableTop="@drawable/upload"
            android:gravity="center"
            android:text="Upload"
            android:textColor="@android:color/black" />
    </LinearLayout>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/large_text" />
</LinearLayout>

Usage in Activities/Fragments

    It's easy to use when we completed setup the bottom sheet. Initializing an instance and show it by this code:
//Initializing a bottom sheet
 BottomSheetDialogFragment bottomSheetDialogFragment = new CustomBottomSheetDialogFragment();

 //show it
 bottomSheetDialogFragment.show(getSupportFragmentManager(), bottomSheetDialogFragment.getTag());
    Full the main activity code:
MainActivity.java
package info.devexchanges.modalbottomsheet;

import android.os.Bundle;
import android.support.design.widget.BottomSheetDialogFragment;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

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

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        View showModalBottomSheet = findViewById(R.id.as_modal);
        showModalBottomSheet.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //Initializing a bottom sheet
                BottomSheetDialogFragment bottomSheetDialogFragment = new CustomBottomSheetDialogFragment();

                //show it
                bottomSheetDialogFragment.show(getSupportFragmentManager(), bottomSheetDialogFragment.getTag());
            }
        });
    }
}
    And the activity layout:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.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"
    android:fitsSystemWindows="true"
    tools:context="com.example.bottomsheetbehavior.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/app_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

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

    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <Button
            android:id="@+id/as_modal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="@dimen/activity_horizontal_margin"
            android:text="@string/modal" />

    </android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
    After running this application, we will have a bottom sheet which displayed when click the Button, you can drag it to change it's state. Moreover, when touching in screen,  the bottom sheet will collapse:

IMPORTANT NOTES:
  • Always set CoordinatorLayout as the root in your Activity layout if you want to show the modal bottom sheet.
  • This design style available only in Design Support Library version 23.2.0 or later, so your dependencies in app/build.gradle must be like this:
  • dependencies {
        compile fileTree(dir: 'libs', include: ['*.jar'])
        compile 'com.android.support:appcompat-v7:23.2.0'
        compile 'com.android.support:design:23.2.0'
    }
    

Conclusions

    You should read my previous post to learn about the "normal" bottom sheet and find out the way to make a complex layout as well as handling each item click event in it. Hope this post can provide once more knowledge about Material Design technology in Android. Finally, you can get my project on @Github.

Share


Previous post
« Prev Post
Next post
Next Post »