63

I would like to keep my dialog open when I press a button. At the moment it's closing.

AlertDialog.Builder builder = new AlertDialog.Builder(this);

builder.setMessage("Are you sure you want to exit?")

   .setCancelable(false)
   .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
       public void onClick(DialogInterface dialog, int id) {
            MyActivity.this.finish();
       }
   })
   .setNegativeButton("No", new DialogInterface.OnClickListener() {
       public void onClick(DialogInterface dialog, int id) {
            dialog.cancel();
       }
   });
AlertDialog alert = builder.create();
Blareprefix
  • 850
  • 2
  • 9
  • 18
  • 4
    Similar question: http://stackoverflow.com/questions/2620444/android-how-to-prevent-dialog-closed-or-remain-dialog-when-button-is-clicked – AlikElzin-kilaka Jun 14 '12 at 16:48
  • in login screen after sending the login details based on response am showing alert with asking once again username for confirmation and ok and cancel dialog interface buttons.if user not enter anything on dialog box and click on ok alert dialog dismissed even am not write dismiss.once i need to check the validation for empty or not then only dismissed if not empty other wise display seterror on edittext please help me am doing in different ways from last one day onwards – Harsha Jul 18 '16 at 05:35
  • 1
    It would be better to [disable the button until the user is ready to go on](http://stackoverflow.com/a/40669929/3681880) rather than to prevent the dialog from closing after the user has already clicked the button. – Suragch Nov 18 '16 at 06:14

7 Answers7

92

Yes, you can. You basically need to:

  1. Create the dialog with DialogBuilder
  2. show() the dialog
  3. Find the buttons in the dialog shown and override their onClickListener

So, create a listener class:

class CustomListener implements View.OnClickListener {
  private final Dialog dialog;

  public CustomListener(Dialog dialog) {
    this.dialog = dialog;
  }

  @Override
  public void onClick(View v) {

    // Do whatever you want here

    // If you want to close the dialog, uncomment the line below
    //dialog.dismiss();
  }
}

Then when showing the dialog use:

AlertDialog dialog = dialogBuilder.create();
dialog.show();
Button theButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
theButton.setOnClickListener(new CustomListener(dialog));

Remember, you need to show the dialog otherwise the button will not be findable. Also, be sure to change DialogInterface.BUTTON_POSITIVE to whatever value you used to add the button. Also note that when adding the buttons in the DialogBuilder you will need to provide onClickListeners - you can not add the custom listener in there, though - the dialog will still dismiss if you do not override the listeners after show() is called.

ישו אוהב אותך
  • 28,609
  • 11
  • 78
  • 96
Kamen
  • 3,575
  • 23
  • 35
  • Why would he create a custom listener if it's already there? He just have to do whatever he wants where that "dialog.cancel();" is. – DallaRosa May 26 '11 at 17:14
  • 1
    @DallaRosa look into AlertController implementation. @Sebastian This is the same what I did and I can confirm that Kamen's answer works. – pawelzieba May 26 '11 at 17:23
  • Thanks for good sample but the "private final Dialog dialog" variable type should be AlertDialog instead of Dialog, also the constrictor method parameter should be AlertDialog as well. – John F Jul 14 '14 at 10:17
  • 2
    I absolutely hate that this works. Providing the listener when the button is created will cause the dialog to close, no matter what the listener has in it. If you wait until it is created (with "null" as the listener), then retrieve the button and add the listener, it works perfectly. Thanks for the help. – beyondtheteal May 13 '15 at 14:59
28

Thanks Sogger for your answer, but there is one change that we have to do here that is, before creating dialog we should set possitive button (and negative button if there is need) to AlertDialog as traditional way, thats it.

Referenced By Sogger.

Here is the sample example ...

AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setMessage("Test for preventing dialog close");
        builder.setTitle("Test");

        builder.setPositiveButton("OK", new OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                // TODO Auto-generated method stub

            }
        });
    builder.setNegativeButton("Cancel", new OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                // TODO Auto-generated method stub

            }
        });

        final AlertDialog dialog = builder.create();
        dialog.show();
        //Overriding the handler immediately after show is probably a better approach than OnShowListener as described below
        dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener()
              {            
                  @Override
                  public void onClick(View v)
                  {
                      Boolean wantToCloseDialog = false;
                      //Do stuff, possibly set wantToCloseDialog to true then...
                      if(wantToCloseDialog)
                          dialog.dismiss();
                      //else dialog stays open. Make sure you have an obvious way to close the dialog especially if you set cancellable to false.
                  }
              });

        dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setOnClickListener(new View.OnClickListener()
          {            
              @Override
              public void onClick(View v)
              {
                  Boolean wantToCloseDialog = true;
                  //Do stuff, possibly set wantToCloseDialog to true then...
                  if(wantToCloseDialog)
                      dialog.dismiss();
                  //else dialog stays open. Make sure you have an obvious way to close the dialog especially if you set cancellable to false.
              }
          });
Shailesh
  • 442
  • 7
  • 14
  • This would have been much more useful as a comment or edit on my answer...but I suppose I did about the same thing with my answer vs. the orignal @Kamen solution, so c'est la vie. – Sogger Jan 23 '15 at 23:33
  • @Sogger Sorry I didn't want to hurt you, but I was newer on stackoverflow at that time. But, As I declared at start of answer, this answer is dedicated to you. Désolé. – Shailesh Nov 10 '16 at 11:36
15

I believe the answer by @Kamen is correct, here is an example of the same approach using an anonymous class instead so it is all in one stream of code:

AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage("Test for preventing dialog close");
AlertDialog dialog = builder.create();
dialog.show();
//Overriding the handler immediately after show is probably a better approach than OnShowListener as described below
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener()
      {            
          @Override
          public void onClick(View v)
          {
              Boolean wantToCloseDialog = false;
              //Do stuff, possibly set wantToCloseDialog to true then...
              if(wantToCloseDialog)
                  dismiss();
              //else dialog stays open. Make sure you have an obvious way to close the dialog especially if you set cancellable to false.
          }
      });

I wrote a more detailed write up to answer the same question here https://stackoverflow.com/a/15619098/579234 which also has examples for other dialogs like DialogFragment and DialogPreference.

Community
  • 1
  • 1
Sogger
  • 15,962
  • 6
  • 43
  • 40
2

This is how I manage to create a persistent popup when changing password.

// Login Activity
AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.SetIcon(Resource.Drawable.padlock);
alert.SetCancelable(false);

var changepass = LayoutInflater.From(this);
var changePassLayout = changepass.Inflate(Resource.Layout.ChangePasswordLayout, null);

alert.SetView(changePassLayout);

txtChangePassword = (EditText)changePassLayout.FindViewById(Resource.Id.txtChangePassword);
txtChangeRetypePassword = (EditText)changePassLayout.FindViewById(Resource.Id.txtChangeRetypePassword);

alert.SetPositiveButton("Change", delegate {
    // You can leave this blank because you override the OnClick event using your custom listener
});

alert.SetNegativeButton("Cancel", delegate {
    Toast.MakeText(this, "Change password aborted!", ToastLength.Short).Show();
});

AlertDialog changePassDialog = alert.Create();
changePassDialog.Show();

// Override OnClick of Positive Button
Button btnPositive = changePassDialog.GetButton((int)Android.Content.DialogButtonType.Positive);
btnPositive.SetOnClickListener(new CustomListener(changePassDialog, empDetailsToValidate.EmployeeID));

// My Custom Class
class CustomListener : Java.Lang.Object, View.IOnClickListener, IDialogInterfaceOnDismissListener
{
    AlertDialog _dialog;
    EditText txtChangePassword;
    EditText txtChangeRetypePassword;

    EmployeeDetails _empDetails;
    string _workingEmployeeID;

    public CustomListener(AlertDialog dialog, string employeeID)
    {
        this._dialog = dialog;
        this._workingEmployeeID = employeeID;
    }
    public void OnClick (View v)
    {
        _empDetails = new EmployeeDetails(v.Context);

        txtChangePassword = (EditText)_dialog.FindViewById (Resource.Id.txtChangePassword);
        txtChangeRetypePassword = (EditText)_dialog.FindViewById (Resource.Id.txtChangeRetypePassword);

        if (!(txtChangePassword.Text.Equals(txtChangeRetypePassword.Text))) {
            Show ();
            Toast.MakeText(v.Context, "Password not match.", ToastLength.Short).Show();
        } else if (txtChangePassword.Text.Trim().Length < 6) {
            Show ();
            Toast.MakeText(v.Context, "Minimum password length is 6 characters.", ToastLength.Short).Show();
        } else if ((txtChangePassword.Text.Equals(LoginActivity.defaultPassword)) || (txtChangePassword.Text == "" || txtChangeRetypePassword.Text == "")) {
            Show ();
            Toast.MakeText(v.Context, "Invalid password. Please use other password.", ToastLength.Short).Show();
        } else {
            int rowAffected = _empDetails.UpdatePassword(_workingEmployeeID, SensoryDB.PassCrypto(txtChangePassword.Text, true));
            if (rowAffected > 0) {
                Toast.MakeText(v.Context, "Password successfully changed!", ToastLength.Short).Show();
                _dialog.Dismiss();
            } else {
                Toast.MakeText(v.Context, "Cant update password!", ToastLength.Short).Show();
                Show();
            }
        }
    }
    public void OnDismiss (IDialogInterface dialog)
    {
        if (!(txtChangePassword.Text.Equals (txtChangePassword.Text))) {
            Show ();
        } else {
            _dialog.Dismiss();
        }
    }
    public void Show ()
    {
        _dialog.Show ();
    }
}

BTW, i use Mono for Android not Eclipse.

Andrew Barber
  • 39,603
  • 20
  • 94
  • 123
klaydze
  • 941
  • 14
  • 36
1

You do not need to create a custom class. You can register a View.OnClickListener for the AlertDialog. This listener will not dismiss the AlertDialog. The trick here is that you need to register the listener after the dialog has been shown, but it can neatly be done inside an OnShowListener. You can use an accessory boolean variable to check if this has already been done so that it will only be done once:

/*
 * Prepare the alert with a Builder.
 */
AlertDialog.Builder b = new AlertDialog.Builder(this);

b.setNegativeButton("Button", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {}
});
this.alert = b.create();

/*
 * Add an OnShowListener to change the OnClickListener on the
 * first time the alert is shown. Calling getButton() before
 * the alert is shown will return null. Then use a regular
 * View.OnClickListener for the button, which will not 
 * dismiss the AlertDialog after it has been called.
 */

this.alertReady = false;
alert.setOnShowListener(new DialogInterface.OnShowListener() {
    @Override
    public void onShow(DialogInterface dialog) {
        if (alertReady == false) {
            Button button = alert.getButton(DialogInterface.BUTTON_NEGATIVE);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //do something
                }
            });
            alertReady = true;
        }
    }
});
0

You can get the Dialog returned from method "show()" alertBuidler.

AlertDialog.Builder adb = new AlertDialog.Builder(YourActivity.this);
//...code to add methods setPositive an setNegative buttons

Call the "show()" method of "adb" and get Dialog

final AlertDialog dialog = adb.show();

So you can call any button of your dialog at any point of code in your activity:

dialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick();//or
dialog.getButton(DialogInterface.BUTTON_NEGATIVE).performClick();//or
dialog.getButton(DialogInterface.BUTTON_NEUTRAL).performClick();
Romeryto
  • 62
  • 3
0

You will probably need to define your own layout and not use the "official" buttons; the behavior you're asking for is not typical of a dialog.

mah
  • 39,056
  • 9
  • 76
  • 93