Search code examples
androidxamarinmodal-dialogandroid-dialogfragment

How to prevent a DialogFragment from dismissing on touch outside?


I am using a DialogFragment which will show a fully customized view, no native button used. I set the dialog cancealable with dialog.SetCanceledOnTouchOutside(true); And when the user touches outside, I want to run some code to determine if the dialog should be dismissed or not. My problem is, when an event is fired (Canceled, Dismissed), the dialog is already dismissed even before the super.Dismiss(); so I can never bypass the dismiss.

I tried many things, override the OnDismiss and OnCancel of the fragment (fired but to late), set the listeners on the dialogBuilder AND/OR on the dialog itself (not fired or too late), override the OnShow to reset the listeners etc ...

Getting stuck with this, Any idea ?

PS: Using Xamarin

public override Dialog OnCreateDialog(Bundle savedInstanceState)
{
    AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this.Activity);
    alertDialogBuilder.SetView(myView);
    AlertDialog dialog = alertDialogBuilder.Create();
    dialog.SetCanceledOnTouchOutside(true);
    return dialog;
}

public override void OnDismiss(IDialogInterface dialog)
{
    //BreakPoint here, already dismissed
    base.OnDismiss(dialog);
}

Solution

  • Do you want to achieve this result? If you click the outside the Dialog, we can detect the click event before the Dialog closed. enter image description here

    You can create a MyAlertDialog inherit the AlertDialog

        public class MyAlertDialog:AlertDialog
    {
        public MyAlertDialog(Context c):base(c) {
    
        }
    
        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
            //Please add following code for watching outside touch
            this.Window.SetFlags(WindowManagerFlags.NotTouchModal, WindowManagerFlags.NotTouchModal);
            this.Window.AddFlags(WindowManagerFlags.WatchOutsideTouch);
        }
    
    
    
        public override bool OnTouchEvent(MotionEvent e)
        {
            //just used for testing.
            var sss = "test";
            //If you want to close the Dialog when click the outside the Dialog part.
            //this.Dismiss();
            return true;
        }
    
    }
    

    Following part is DialogFragment.

        public class MyDialog:Android.Support.V4.App.DialogFragment
    {
    
        public override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
    
        }
    
    
        public override Dialog OnCreateDialog(Bundle savedInstanceState)
        {
    
    
            MyAlertDialog alertDialogBuilder = new MyAlertDialog(this.Activity);
            alertDialogBuilder.SetTitle("MyDialog");
            alertDialogBuilder.SetCanceledOnTouchOutside(true);
            return alertDialogBuilder;
        }
    
    
    
        public override void OnPause()
        {
            base.OnPause();
        }
    
        public override void OnCancel(IDialogInterface dialog)
        {
            base.OnCancel(dialog);
        }
    
        public override void OnDismiss(IDialogInterface dialog)
        {
            base.OnDismiss(dialog);
        }
    }
    

    Click the button to push the Dialog.

    private void BtnClick_Click(object sender, System.EventArgs e)
        {
            MyDialog dialog = new MyDialog();
            dialog.Show(SupportFragmentManager, "dialog");
        }