Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

BottomSheetDialog remains hidden after dismiss by dragging down

I am pretty curious about the behavior of the BottomSheetDialog when it is dismissed : when the user draggs it down to hide it, it will remain hidden, even if bottomSheetDialog#show() is called after. This only happens when it is dragged down, not when the user touches outside or when bottomSheetDialog#dismiss() is called programatically.

It is really annoying because I have a pretty big bottomSheetDialog with a recyclerview inside, and I have to create a new one every time I want to show the bottomSheetDialog.

So instead of just doing this :

if(bottomSheetDialog != null){
   bottomSheetDialog.show();
else{
   createNewBottomSheetDialog();
}

I have to create one every time.

Am I missing something or is it the normal behavior ? (Btw I use appcompat-v7:23.2.1)

like image 770
David Seroussi Avatar asked Aug 06 '16 13:08

David Seroussi


People also ask

How to close bottomSheetDialog?

We use bottomSheetDialog. dismiss() to close the dialog once an element is clicked.

How do I disable BottomSheetDialogFragment dragging?

Disable drag of BottomSheetDialogFragment Even if we have made the BottomSheetDialogFragment as expanded, user can hold the top part of the BottomSheet and drag to show peek view. It can also be disabled by overriding onStateChanged() . This will set the expanded state even if user drags the view.

How do I make my bottom sheet not dismissable?

setCancelable(false) will prevent the bottom sheet dismiss on back press also.

How do I allow outside touch for bottomSheetDialog?

just include <layout /> and attach to BottomSheetBehavior , it will work fine.


2 Answers

So I finally managed to solve this problem by looking directly into the BottomSheetDialog implementation, and I discovered it was nothing but a simple Dialog wrapped into a regular BottomSheet.
The problem was in the BottomSheetCallBack :

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

The problem occurs when the state HIDDEN is reached which happens when the dialog is dismissed by being dragged down. After that the dialog stays hidden even if bottomSheetDialog.show() is called. The most simple fix I found was to remove this state and replace it by the COLLAPSED state.

I create a classCustomBottomSheetDialog, copied the entire BottomSheetDialog class and added a single line to fix the problem :

@Override
    public void onStateChanged(@NonNull View bottomSheet,
                               @BottomSheetBehavior.State int newState) {

        if (newState == CustomBottomSheetBehavior.STATE_HIDDEN) {

            dismiss();
            bottomSheetBehavior.setState(CustomBottomSheetBehavior.STATE_COLLAPSED);
        }
    }

Here is the final code:

public class CustomBottomSheetDialog extends AppCompatDialog {

    public CustomBottomSheetDialog (@NonNull Context context) {
        this(context, 0);
    }

    public CustomBottomSheetDialog (@NonNull Context context, @StyleRes int theme) {
        super(context, getThemeResId(context, theme));
        // We hide the title bar for any style configuration. Otherwise, there will be a gap
        // above the bottom sheet when it is expanded.
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
    }

    protected CustomBottomSheetDialog (@NonNull Context context, boolean cancelable,
            OnCancelListener cancelListener) {
        super(context, cancelable, cancelListener);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
    }

    @Override
    public void setContentView(@LayoutRes int layoutResId) {
        super.setContentView(wrapInBottomSheet(layoutResId, null, null));
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().setLayout(
                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
    }

    @Override
    public void setContentView(View view) {
        super.setContentView(wrapInBottomSheet(0, view, null));
    }

    @Override
    public void setContentView(View view, ViewGroup.LayoutParams params) {
        super.setContentView(wrapInBottomSheet(0, view, params));
    }

    private View wrapInBottomSheet(int layoutResId, View view, ViewGroup.LayoutParams params) {
        final CoordinatorLayout coordinator = (CoordinatorLayout) View.inflate(getContext(),
                R.layout.design_bottom_sheet_dialog, null);
        if (layoutResId != 0 && view == null) {
            view = getLayoutInflater().inflate(layoutResId, coordinator, false);
        }
        FrameLayout bottomSheet = (FrameLayout) coordinator.findViewById(R.id.design_bottom_sheet);
        BottomSheetBehavior.from(bottomSheet).setBottomSheetCallback(mBottomSheetCallback);
        if (params == null) {
            bottomSheet.addView(view);
        } else {
            bottomSheet.addView(view, params);
        }
        // We treat the CoordinatorLayout as outside the dialog though it is technically inside
        if (shouldWindowCloseOnTouchOutside()) {
            coordinator.findViewById(R.id.touch_outside).setOnClickListener(
                    new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            if (isShowing()) {
                                cancel();
                            }
                        }
                    });
        }
        return coordinator;
    }

    private boolean shouldWindowCloseOnTouchOutside() {
        if (Build.VERSION.SDK_INT < 11) {
            return true;
        }
        TypedValue value = new TypedValue();
        //noinspection SimplifiableIfStatement
        if (getContext().getTheme()
                .resolveAttribute(android.R.attr.windowCloseOnTouchOutside, value, true)) {
            return value.data != 0;
        }
        return false;
    }

    private static int getThemeResId(Context context, int themeId) {
        if (themeId == 0) {
            // If the provided theme is 0, then retrieve the dialogTheme from our theme
            TypedValue outValue = new TypedValue();
            if (context.getTheme().resolveAttribute(
                    R.attr.bottomSheetDialogTheme, outValue, true)) {
                themeId = outValue.resourceId;
            } else {
                // bottomSheetDialogTheme is not provided; we default to our light theme
                themeId = R.style.Theme_Design_Light_BottomSheetDialog;
            }
        }
        return themeId;
    }

    private BottomSheetBehavior.BottomSheetCallback mBottomSheetCallback
            = new BottomSheetBehavior.BottomSheetCallback() {
        @Override
        public void onStateChanged(@NonNull View bottomSheet,
                @BottomSheetBehavior.State int newState) {
            if (newState == BottomSheetBehavior.STATE_HIDDEN) {
                dismiss();
                bottomSheetBehavior.setState(CustomBottomSheetBehavior.STATE_COLLAPSED);
            }
        }

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

}
like image 134
David Seroussi Avatar answered Oct 21 '22 18:10

David Seroussi


Update: The problem has been resolved at some version of the support library. I don't really know the exact version that fixes it but in 27.0.2 it is fixed.

Note: The URL does no longer refer to the issue described due to some modification on the URL schema by Google.

A workaround better than copying the whole class just to add a single line

// Fix BottomSheetDialog not showing after getting hidden when the user drags it down
    myBottomSheetDialog.setOnShowListener(new DialogInterface.OnShowListener() {
        @Override
        public void onShow(DialogInterface dialogInterface) {
            BottomSheetDialog bottomSheetDialog = (BottomSheetDialog) dialogInterface;
            FrameLayout bottomSheet = (FrameLayout) bottomSheetDialog
                    .findViewById(android.support.design.R.id.design_bottom_sheet);
            BottomSheetBehavior.from(bottomSheet).setState(BottomSheetBehavior.STATE_COLLAPSED);
        }
    });

see: https://code.google.com/p/android/issues/detail?id=202396#c7

like image 29
Kh5 Avatar answered Oct 21 '22 16:10

Kh5