Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent a dialog from closing when a button is clicked

I have a dialog with EditText for input. When I click the "yes" button on dialog, it will validate the input and then close the dialog. However, if the input is wrong, I want to remain in the same dialog. Every time no matter what the input is, the dialog should be automatically closed when I click on the "no" button. How can I disable this? By the way, I have used PositiveButton and NegativeButton for the button on dialog.

like image 443
user304881 Avatar asked Apr 12 '10 07:04

user304881


People also ask

How do you prevent a dialog from closing when a button is clicked?

If you wish to prevent a dialog box from closing when one of these buttons is pressed you must replace the common button handler for the actual view of the button.

How do I stop dialog close on click outside Android?

Simply, alertDialog. setCancelable(false); prevent user from click outside of Dialog Box.

Can you have an alert dialog without any buttons if not why?

You can do this very easily. AlertDialog. Builder alertDialogBuilder = new AlertDialog. Builder(context); // set title alertDialogBuilder.

How do you dismiss dialog with click on outside of dialog?

You can use dialog. setCanceledOnTouchOutside(true); which will close the dialog if you touch outside of the dialog.


2 Answers

Here are some solutions for all types of dialogs including a solution for AlertDialog.Builder that will work on all API levels (works below API 8, which the other answer here does not). There are solutions for AlertDialogs using AlertDialog.Builder, DialogFragment, and DialogPreference.

Below are the code examples showing how to override the default common button handler and prevent the dialog from closing for these different forms of dialogs. All the examples show how to prevent the positive button from closing the dialog.

Note: A description of how the dialog closing works under the hood for the base android classes and why the following approaches are chosen follows after the examples, for those who want more details


AlertDialog.Builder - Change default button handler immediately after show()

AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setMessage("Test for preventing dialog close"); builder.setPositiveButton("Test",          new DialogInterface.OnClickListener()         {             @Override             public void onClick(DialogInterface dialog, int which)             {                 //Do nothing here because we override this button later to change the close behaviour.                  //However, we still need this because on older versions of Android unless we                  //pass a handler the button doesn't get instantiated             }         }); 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.           }       });        

DialogFragment - override onResume()

@Override public Dialog onCreateDialog(Bundle savedInstanceState) {     AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());     builder.setMessage("Test for preventing dialog close");     builder.setPositiveButton("Test",          new DialogInterface.OnClickListener()         {             @Override             public void onClick(DialogInterface dialog, int which)             {                 //Do nothing here because we override this button later to change the close behaviour.                  //However, we still need this because on older versions of Android unless we                  //pass a handler the button doesn't get instantiated             }         });     return builder.create(); }  //onStart() is where dialog.show() is actually called on  //the underlying dialog, so we have to do it there or  //later in the lifecycle. //Doing it in onResume() makes sure that even if there is a config change  //environment that skips onStart then the dialog will still be functioning //properly after a rotation. @Override public void onResume() {     super.onResume();         final AlertDialog d = (AlertDialog)getDialog();     if(d != null)     {         Button positiveButton = (Button) d.getButton(Dialog.BUTTON_POSITIVE);         positiveButton.setOnClickListener(new View.OnClickListener()                 {                     @Override                     public void onClick(View v)                     {                         Boolean wantToCloseDialog = false;                         //Do stuff, possibly set wantToCloseDialog to true then...                         if(wantToCloseDialog)                             d.dismiss();                         //else dialog stays open. Make sure you have an obvious way to close the dialog especially if you set cancellable to false.                     }                 });     } } 

DialogPreference - override showDialog()

@Override protected void onPrepareDialogBuilder(Builder builder) {     super.onPrepareDialogBuilder(builder);     builder.setPositiveButton("Test", this);   //Set the button here so it gets created }  @Override protected void showDialog(Bundle state) {            super.showDialog(state);    //Call show on default first so we can override the handlers      final AlertDialog d = (AlertDialog) getDialog();     d.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)                         d.dismiss();                     //else dialog stays open. Make sure you have an obvious way to close the dialog especially if you set cancellable to false.                 }             }); } 

Explanation of approaches:

Looking through Android source code the AlertDialog default implementation works by registering a common button handler to all the actual buttons in OnCreate(). When a button is clicked the common button handler forwards the click event to whatever handler you passed in setButton() then calls dismisses the dialog.

If you wish to prevent a dialog box from closing when one of these buttons is pressed you must replace the common button handler for the actual view of the button. Because it is assigned in OnCreate(), you must replace it after the default OnCreate() implementation is called. OnCreate is called in the process of the show() method. You could create a custom Dialog class and override OnCreate() to call the super.OnCreate() then override the button handlers, but if you make a custom dialog you don't get the Builder for free, in which case what is the point?

So, in using a dialog the way it is designed but with controlling when it is dismissed, one approach is to call dialog.Show() first, then obtain a reference to the button using dialog.getButton() to override the click handler. Another approach is to use setOnShowListener() and implement finding the button view and replacing the handler in the OnShowListener. The functional difference between the two is 'almost' nill, depending on what thread originally creates the dialog instance. Looking through the source code, the onShowListener gets called by a message posted to a handler running on the thread that created that dialog. So, since your OnShowListener is called by a message posted on the message queue it is technically possible that calling your listener is delayed some time after show completes.

Therefore, I believe the safest approach is the first: to call show.Dialog(), then immediately in the same execution path replace the button handlers. Since your code that calls show() will be operating on the main GUI thread, it means whatever code you follow show() with will be executed before any other code on that thread, whereas the timing of the OnShowListener method is at the mercy of the message queue.

like image 28
Sogger Avatar answered Sep 19 '22 03:09

Sogger


EDIT: This only works on API 8+ as noted by some of the comments.

This is a late answer, but you can add an onShowListener to the AlertDialog where you can then override the onClickListener of the button.

final AlertDialog dialog = new AlertDialog.Builder(context)         .setView(v)         .setTitle(R.string.my_title)         .setPositiveButton(android.R.string.ok, null) //Set to null. We override the onclick         .setNegativeButton(android.R.string.cancel, null)         .create();  dialog.setOnShowListener(new DialogInterface.OnShowListener() {      @Override     public void onShow(DialogInterface dialogInterface) {          Button button = ((AlertDialog) dialog).getButton(AlertDialog.BUTTON_POSITIVE);         button.setOnClickListener(new View.OnClickListener() {              @Override             public void onClick(View view) {                 // TODO Do something                  //Dismiss once everything is OK.                 dialog.dismiss();             }         });     } }); dialog.show(); 
like image 114
Tom Bollwitt Avatar answered Sep 18 '22 03:09

Tom Bollwitt