Search code examples
androiddialogandroid-dialogfragmentdialogfragmentbottom-sheet

BottomSheetDialogFragment - listen to dismissed by user event


How can I listen to a FINAL dismissal of a BottomSheetDialogFragment? I want to save user changes on the final dismissal only...

I tried following:

Method 1

This only fires, if the dialog is dismissed by swiping it down (not on back press or on touch outside)

@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
    Dialog d = super.onCreateDialog(savedInstanceState);
    d.setOnShowListener(new DialogInterface.OnShowListener() {
        @Override
        public void onShow(DialogInterface dialog) {

            BottomSheetDialog d = (BottomSheetDialog) dialog;   
            FrameLayout bottomSheet = (FrameLayout) dialog.findViewById(android.support.design.R.id.design_bottom_sheet);

            BottomSheetBehavior behaviour = BottomSheetBehavior.from(bottomSheet);
            behaviour.setState(BottomSheetBehavior.STATE_EXPANDED);
            behaviour.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
                @Override
                public void onStateChanged(@NonNull View bottomSheet, int newState) {
                    if (newState == BottomSheetBehavior.STATE_HIDDEN)
                    {
                        // Bottom Sheet was dismissed by user! But this is only fired, if dialog is swiped down! Not if touch outside dismissed the dialog or the back button
                        Toast.makeText(MainApp.get(), "HIDDEN", Toast.LENGTH_SHORT).show();
                        dismiss();
                    }
                }

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

                }
            });
        }
    });
    return d;
}

Method 2

This does not allow me to distinguish between a final dismissal and one that is coming from a screen rotation or activity recreation...

 @Override
public void onDismiss(DialogInterface dialog)
{
    super.onDismiss(dialog);
    // this works fine but fires one time too often for my use case, it fires on screen rotation as well, although this is a temporarily dismiss only
    Toast.makeText(MainApp.get(), "DISMISSED", Toast.LENGTH_SHORT).show();
}

Question

How can I listen to an event that indicates, that the user has finished the dialog?


Solution

  • Although all similar questions on SO suggest using onDismiss I think following is the correct solution:

    @Override
    public void onCancel(DialogInterface dialog)
    {
        super.onCancel(dialog);
        Toast.makeText(MainApp.get(), "CANCEL", Toast.LENGTH_SHORT).show();
    }
    

    This fires if:

    * the user presses back
    * the user presses outside of the dialog
    

    This fires NOT:

    * on screen rotation and activity recreation
    

    Solution

    Combine onCancel and BottomSheetBehavior.BottomSheetCallback.onStateChanged like following:

    public class Dailog extends BottomSheetDialogFragment
    {
        @Override
        public void onCancel(DialogInterface dialog)
        {
            super.onCancel(dialog);
            handleUserExit();
        }
    
        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState)
        {
            Dialog d = super.onCreateDialog(savedInstanceState);
            d.setOnShowListener(new DialogInterface.OnShowListener() {
                @Override
                public void onShow(DialogInterface dialog) {
                    BottomSheetDialog d = (BottomSheetDialog) dialog;
                    FrameLayout bottomSheet = (FrameLayout) d.findViewById(android.support.design.R.id.design_bottom_sheet);
                    BottomSheetBehavior behaviour = BottomSheetBehavior.from(bottomSheet);
                    behaviour.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
                        @Override
                        public void onStateChanged(@NonNull View bottomSheet, int newState) {
                            if (newState == BottomSheetBehavior.STATE_HIDDEN)
                            {
                                handleUserExit();
                                dismiss();
                            }
                        }
    
                        @Override
                        public void onSlide(@NonNull View bottomSheet, float slideOffset) {
    
                        }
                    });
                }
            });
            return d;
        }
    
        private void handleUserExit()
        {
            Toast.makeText(MainApp.get(), "TODO - SAVE data or similar", Toast.LENGTH_SHORT).show();
        }
    }