1

I have a DialogFragment that allows the user to input long messages. By default, if the user clicks outside the DialogFragment or back button, the dialog is dismissed and the user inputs will be lost.

If I use "this.isCancelable = false", it entirely prevents the back button/outside click from firing, which I do not want.

Instead, I want to have a popup message to appear with "Are you sure you want to discard changes", and dismiss DialogFragment only if the user clicks yes then. How should I do this?

Edit: also tried to solve this with flags but still having issues.

Add to DialogFragment's "override fun OnResume()"

        //FLAG_WATCH_OUTSIDE_TOUCH requires FLAG_NOT_TOUCH_MODAL to work
        dialog?.window?.addFlags(
            WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
        )
        dialog?.window?.addFlags(
            WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
        )

        dialog?.window?.decorView?.setOnTouchListener { v, event ->
            if (event.action == MotionEvent.ACTION_OUTSIDE) {
                //action to show a message
            }
            true
        }

Problem with this approach is due to FLAG_NOT_TOUCH_MODAL, I can now click items behind the dialog, which messes up the navigation controller and breaks the app. Is it possible to monitor MotionEvent.ACTION_OUTSIDE, but prevents any actual clicks outside the dialog?

PhantomCosmos
  • 119
  • 1
  • 7

2 Answers2

0

You can set setCanceledOnTouchOutside boolean to true and use the below method for events.

dialog.setOnCancelListener(
    new DialogInterface.OnCancelListener() {
        @Override
        public void onCancel(DialogInterface dialog) {
            //When you touch outside of dialog bounds, 
            //the dialog gets canceled and this method executes.
        }
    }
);

Show toast or dialog which you want for user confirmation in this onCancel method.

Hope this helps!

OR

1 Set the flag-FLAG_NOT_TOUCH_MODAL for your dialog's window attribute

Window window = this.getWindow();
window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);

2 Add another flag to windows properties, FLAG_WATCH_OUTSIDE_TOUCH - this one is for dialog to receive touch event outside its visible region.

3 Override onTouchEvent() of dialog and check for action type. if the action type is 'MotionEvent.ACTION_OUTSIDE' means, the user is interacting outside the dialog region. So in this case, you can open another dialog for user confirmation.

public boolean onTouchEvent(MotionEvent event)  
{  
       if(event.getAction() == MotionEvent.ACTION_OUTSIDE){  
        System.out.println("TOuch outside the dialog");  
               this.dismiss();  
       }  
       return false;  
}  
Rushabh Shah
  • 680
  • 4
  • 22
0

Found the solution, credit to @Unknownweirdo, How to dismiss the dialog with click on outside of the dialog?

Kotlin code:

    override fun onResume() {
        super.onResume()

        dialog?.window?.addFlags(
            WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
        )

        dialog?.window?.decorView?.setOnTouchListener { v, event ->
            if (event.action == MotionEvent.ACTION_DOWN) {
                val dialogBounds = Rect()
                v.getHitRect(dialogBounds)
                if (!dialogBounds.contains(event.x.toInt(), event.y.toInt())) {
                    // You have clicked the grey area
                    logicToConfirmDiscardingChange()
                    false // stop activity closing
                }
            }
            true
        }
    }

PhantomCosmos
  • 119
  • 1
  • 7