How to use BottomSheetDialog?
Asked Answered
S

6

38

I want to try BottomSheetDialog introduced in Android Support Library 23.2 but it doesn't seem to work correctly. Here is what the doc says:

While BottomSheetBehavior captures the persistent bottom sheet case, this release also provides a BottomSheetDialog and BottomSheetDialogFragment to fill the modal bottom sheets use case. Simply replace AppCompatDialog or AppCompatDialogFragment with their bottom sheet equivalents to have your dialog styled as a bottom sheet."

So I changed my AppCompatDialog to BottomSheetDialog:

package my.package.ui.dialog;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.support.design.widget.BottomSheetDialog;

import my.package.R;

public class AccountActionsDialog extends BottomSheetDialog {
    public AccountActionsDialog(Context context) {
        super(context);

        if (context instanceof Activity) {
            setOwnerActivity((Activity) context);
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getLayoutInflater().inflate(R.layout.dialog_account_actions, null));
    }
}

Here is my layout file:

<?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="wrap_content"
    android:orientation="vertical">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#ff0000"
        android:padding="16dp"
        android:text="Delete account"
        android:textColor="#ffffff" />

</LinearLayout>

Then I use the following code in my Activity:

new AccountActionsDialog(this).show();

My screen becomes dimmed but the content of my dialog is not visible. Any thoughts on what might be missing? It works fine when I use AppCompatDialog instead.

Stalwart answered 25/2, 2016 at 3:7 Comment(6)
Is there a particular reason you aren't using setContentView(R.layout.dialog_account_actions)?Dyson
Yes. Initially I inflated the root view first and used findViewById() to find all the subviews that I need and set proper listeners for them. I simplified the code for this example and forgot to change this part. The issue remains no matter how the layout is set.Stalwart
This is most definitely a bug in the support library - please file one at b.android.com with a small sample project and include a link here so I can bring it up to the team - for an even crazier behavior - set your LinearLayout to a height of ~250dp.Dyson
@IgorBubelov: see github.com/rey5137/Material/wiki/BottomSheet git probably help uBasswood
@Dyson done, thanksStalwart
Written an article on how to use BottomSheetDialog in Android . Hopefully it help other Android developersSymbolic
B
12

Instead of having a separate class, you can simply create an instance for BottomSheetDialog in your Activity/Fragment like following and you can use it. It is very easier and simpler I think.

val dialog = BottomSheetDialog(this)
val bottomSheet = layoutInflater.inflate(R.layout.bottom_sheet, null)

bottomSheet.buttonSubmit.setOnClickListener { dialog.dismiss() }
        
dialog.setContentView(bottomSheet)
dialog.show()
Blat answered 12/7, 2018 at 6:44 Comment(0)
S
4

This is the layout file of BottomSheetDialog.

<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:soundEffectsEnabled="false">

<FrameLayout
        android:id="@+id/design_bottom_sheet"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        app:layout_behavior="@string/bottom_sheet_behavior"
        style="?attr/bottomSheetStyle"/>

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

Your content view is inside the view design_bottom_sheet, it will be positioned center vertically by CoordinatorLayout, and BottomSheetBehavior will offset it.

mParentHeight = parent.getHeight();
mMinOffset = Math.max(0, mParentHeight - child.getHeight());
mMaxOffset = mParentHeight - mPeekHeight;
if (mState == STATE_EXPANDED) {
    ViewCompat.offsetTopAndBottom(child, mMinOffset);
} else if (mHideable && mState == STATE_HIDDEN) {
    ViewCompat.offsetTopAndBottom(child, mParentHeight);
} else if (mState == STATE_COLLAPSED) {
    ViewCompat.offsetTopAndBottom(child, mMaxOffset);
}

It intented to positon design_bottom_sheet at mMaxOffset, but actually the initial getTop of the child view is not 0, but (mParentHeight - childHeight) / 2, so you view if offset more than the desired offset.

Find the view design_bottom_sheet and set its gravity to Gravity.TOP | Gravity.CENTER_HORIZONTAL will fix it. But, if the childHeight is less than mPeekHeight, there will be blank area below you content view.

However, if peekHeight > childHeight, the mMaxOffset will less than mMinOffset, which will cause weird behavior.

Maybe the code should be changed to

mMaxOffset = Math.max((mParentHeight - mPeekHeight), mMinOffset);

insted of

mMaxOffset = mParentHeight - child.getHeight();
Shuman answered 25/2, 2016 at 5:58 Comment(2)
This is the issue I'm seeing too. The Framelayout that wraps your content view is centered vertically for some reason. When the BottomSheetBehavior then lays out the Framelayout, it starts with a Y value > 0. All of the math inside that behavior is meant to work by offsetting the view from the TOP of the parent, resulting in the content being much lower than expected (off screen)Yasmin
@Edward Kimmel FrameLayout will check whether you set gravity top, bottom or center_vertical, if none of these is set, FrameLayout will layout child at top. However, CoordinatorLayout.layoutChild uses Gravity.apply to layout its children, In Gravity.apply, if none of these gravity is set, it will layout child view at center of the parent. See Gravity.applyShuman
W
2

I was expriencing the same issue, dimmed background and content not visible. Here is how I managed to workaround it by setting the content view in setupDialog() hidden method.

public class CustomBottomSheetDialogFragment extends BottomSheetDialogFragment {

    private TextView mOffsetText;
    private TextView mStateText;
    private BottomSheetBehavior.BottomSheetCallback mBottomSheetBehaviorCallback = new BottomSheetBehavior.BottomSheetCallback() {

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

        }

        @Override
        public void onSlide(@NonNull View bottomSheet, float slideOffset) {
            setOffsetText(slideOffset);
        }
    };
    private LinearLayoutManager mLinearLayoutManager;
    private ApplicationAdapter mAdapter;

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        return super.onCreateDialog(savedInstanceState);
    }

    @Override
    public void onViewCreated(View contentView, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(contentView, savedInstanceState);
    }

    @Override
    public void setupDialog(Dialog dialog, int style) {
        super.setupDialog(dialog, style);
        View contentView = View.inflate(getContext(), R.layout.bottom_sheet_dialog_content_view, null);
        dialog.setContentView(contentView);
       mBottomSheetBehavior = BottomSheetBehavior.from(((View) contentView.getParent()));
        if (mBottomSheetBehavior != null) {
            mBottomSheetBehavior.setBottomSheetCallback(mBottomSheetBehaviorCallback);   
        }
        mOffsetText = (TextView) contentView.findViewById(R.id.offsetText);
        mStateText = (TextView) contentView.findViewById(R.id.stateText);
    }

}

And the layout:

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


    <TextView
        android:id="@+id/offsetText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@android:color/black" />

    <TextView
        android:id="@+id/stateText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@android:color/black" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>
Windburn answered 25/2, 2016 at 17:19 Comment(1)
for obtaining behavior you can also use BottomSheetBehavior.from(View v) although it throws exceptionsContrabass
Y
2

Here's the issue on code.google.com https://code.google.com/p/android/issues/detail?id=201793

An issue some users are seeing boils down to the FrameLayout that wraps our content view being centered vertically. The BottomSheetBehavior only works if this view is top aligned. I haven't figured out what causes the FrameLayout to become centered vertically yet, but here's a possible workaround:

View contentView = ...
// You may have to measure your content view first.
dialog.setContentView(contentView);

// Change this to a percentage or a constant, whatever you want to do.
// The default is 1024 - any views smaller than this will be pulled off 
// the bottom of the screen.
float peekHeight = contentView.getMeasuredHeight();

View parent = (View)contentView.getParent();
BottomSheetBehavior behavior = BottomSheetBehavior.from(parent);
behavior.setPeekHeight(peekHeight);
CoordinatorLayout.LayoutParams layoutParams = 
   (CoordinatorLayout.LayoutParams)parent.getLayoutParams();
layoutParams.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
Yasmin answered 25/2, 2016 at 17:24 Comment(1)
This doesn't fix anything.Slaw
S
1

It started to work when I set fixed height for my TextView (200dp), although for some height values it still behaves incorrectly. Obviously it's an issue of support lib. There are already few reports related to BottomSheetDialog in the bug tracker:

https://code.google.com/p/android/issues/detail?id=201793&sort=-opened&colspec=ID%20Status%20Priority%20Owner%20Summary%20Stars%20Reporter%20Opened

https://code.google.com/p/android/issues/detail?id=201826

Stalwart answered 26/2, 2016 at 3:28 Comment(0)
V
0

To open bottom sheet dialog use following code.

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


    <TextView
        android:id="@+id/choosetxt"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="15dp"
        android:text="Please verify your SIM Card."
        android:textAlignment="center"
        android:textColor="@color/black"
        android:textSize="20dp"
        android:textStyle="bold" />

    <LinearLayout
        android:id="@+id/layoutEdit"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:orientation="horizontal"
        android:padding="8dp">

        <TextView
            android:id="@+id/tv_bottom_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:layout_marginRight="10dp"
            android:textAlignment="center"
            android:textColor="@color/black"
            android:textSize="16sp" />

    </LinearLayout>

    <ProgressBar
        android:id="@+id/loadingBottom_progress_xml"
        style="?android:attr/progress"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_gravity="center"
        android:visibility="gone" />

    <TextView
        android:id="@+id/tv_inProgress"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:gravity="center"
        android:text="Verification in progress."
        android:textColor="@color/black"
        android:textSize="15dp"
        android:textStyle="bold"
        android:visibility="invisible" />

    <Button
        android:id="@+id/btn_verifyss"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="20dp"
        android:layout_marginRight="10dp"
        android:layout_marginBottom="10dp"
        android:background="@drawable/roundbutton"
        android:text="START SIM VERIFICATION"
        android:textColor="@color/white" />

    <LinearLayout
        android:id="@+id/linear_congrats"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:orientation="vertical"
        android:visibility="gone">


        <TextView
            android:id="@+id/tv_verifys"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:gravity="center"
            android:text="Congratulations. Given Number Successfully Verified."
            android:textColor="@color/black"
            android:textSize="15dp"
            android:textStyle="bold" />

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="150dp"
            android:src="@drawable/success" />
    </LinearLayout>
</LinearLayout>
Verbose answered 2/9, 2023 at 6:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.