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

后端 未结 18 1952
无人及你
无人及你 2020-11-21 23:59

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

相关标签:
18条回答
  • 2020-11-22 00:21

    This code will work for you, because i had a simmilar problem and this worked for me. :)

    1- Override Onstart() method in your fragment-dialog class.

    @Override
    public void onStart() {
        super.onStart();
        final AlertDialog D = (AlertDialog) getDialog();
        if (D != null) {
            Button positive = (Button) D.getButton(Dialog.BUTTON_POSITIVE);
            positive.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View arg0) {
                    if (edittext.equals("")) {
       Toast.makeText(getActivity(), "EditText empty",Toast.LENGTH_SHORT).show();
                    } else {
                    D.dismiss(); //dissmiss dialog
                    }
                }
            });
        }
    }
    
    0 讨论(0)
  • 2020-11-22 00:21

    This is probably very late reply, but using setCancelable will do the trick.

    alertDial.setCancelable(false);
    
    0 讨论(0)
  • 2020-11-22 00:25
    public class ComentarDialog extends DialogFragment{
    private EditText comentario;
    
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
    
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    
        LayoutInflater inflater = LayoutInflater.from(getActivity());
        View v = inflater.inflate(R.layout.dialog_comentar, null);
        comentario = (EditText)v.findViewById(R.id.etxt_comentar_dialog);
    
        builder.setTitle("Comentar")
               .setView(v)
               .setPositiveButton("OK", null)
               .setNegativeButton("CANCELAR", new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int id) {
    
                   }
               });
    
        return builder.create();
    }
    
    @Override
    public void onStart() {
        super.onStart();
    
        //Obtenemos el AlertDialog
        AlertDialog dialog = (AlertDialog)getDialog();
    
        dialog.setCanceledOnTouchOutside(false);
        dialog.setCancelable(false);//Al presionar atras no desaparece
    
        //Implementamos el listener del boton OK para mostrar el toast
        dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(TextUtils.isEmpty(comentario.getText())){
                   Toast.makeText(getActivity(), "Ingrese un comentario", Toast.LENGTH_SHORT).show();
                   return;
                }
                else{
                    ((AlertDialog)getDialog()).dismiss();
                }
            }
        });
    
        //Personalizamos
        Resources res = getResources();
    
        //Buttons
        Button positive_button = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
        positive_button.setBackground(res.getDrawable(R.drawable.btn_selector_dialog));
    
        Button negative_button =  dialog.getButton(DialogInterface.BUTTON_NEGATIVE);
        negative_button.setBackground(res.getDrawable(R.drawable.btn_selector_dialog));
    
        int color = Color.parseColor("#304f5a");
    
        //Title
        int titleId = res.getIdentifier("alertTitle", "id", "android");
        View title = dialog.findViewById(titleId);
        if (title != null) {
            ((TextView) title).setTextColor(color);
        }
    
        //Title divider
        int titleDividerId = res.getIdentifier("titleDivider", "id", "android");
        View titleDivider = dialog.findViewById(titleDividerId);
        if (titleDivider != null) {
            titleDivider.setBackgroundColor(res.getColor(R.color.list_menu_divider));
        }
    }
    }
    
    0 讨论(0)
  • 2020-11-22 00:26

    Inspired by Tom's answer, I believe the idea here is:

    • Set the onClickListener during the creation of the dialog to null
    • Then set a onClickListener after the dialog is shown.

    You can override the onShowListener like Tom. Alternatively, you can

    1. get the button after calling AlertDialog's show()
    2. set the buttons' onClickListener as follows (slightly more readable I think).

    Code:

    AlertDialog.Builder builder = new AlertDialog.Builder(context);
    // ...
    final AlertDialog dialog = builder.create();
    dialog.show();
    // now you can override the default onClickListener
    Button b = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
    b.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Log.i(TAG, "ok button is clicked");
            handleClick(dialog);
        }
    });
    
    0 讨论(0)
  • 2020-11-22 00:28

    An alternate solution

    I would like to present an alternate answer from a UX perspective.

    Why would you want to prevent a dialog from closing when a button is clicked? Presumably it is because you have a custom dialog in which the user hasn't made a choice or hasn't completely filled everything out yet. And if they are not finished, then you shouldn't allow them to click the positive button at all. Just disable it until everything is ready.

    The other answers here give lots of tricks for overriding the positive button click. If that were important to do, wouldn't Android have made a convenient method to do it? They didn't.

    Instead, the Dialogs design guide shows an example of such a situation. The OK button is disabled until the user makes a choice. No overriding tricks are necessary at all. It is obvious to the user that something still needs to be done before going on.

    How to disable the positive button

    See the Android documentation for creating a custom dialog layout. It recommends that you place your AlertDialog inside a DialogFragment. Then all you need to do is set listeners on the layout elements to know when to enable or disable the positive button.

    • If you custom dialog has radio buttons, then use RadioGroup.OnCheckedChangeListener.
    • If your custom dialog has check boxes, then use CompoundButton.OnCheckedChangeListener.
    • If your custom dialog has an EditText, then use TextWatcher.

    The positive button can be disabled like this:

    AlertDialog dialog = (AlertDialog) getDialog();
    dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
    

    Here is an entire working DialogFragment with a disabled positive button such as might be used in the image above.

    import android.support.v4.app.DialogFragment;
    import android.support.v7.app.AlertDialog;
    
    public class MyDialogFragment extends DialogFragment {
    
        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
    
            // inflate the custom dialog layout
            LayoutInflater inflater = getActivity().getLayoutInflater();
            View view = inflater.inflate(R.layout.my_dialog_layout, null);
    
            // add a listener to the radio buttons
            RadioGroup radioGroup = (RadioGroup) view.findViewById(R.id.radio_group);
            radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(RadioGroup radioGroup, int i) {
                    // enable the positive button after a choice has been made
                    AlertDialog dialog = (AlertDialog) getDialog();
                    dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(true);
                }
            });
    
            // build the alert dialog
            AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
            builder.setView(view)
                    .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int id) {
                            // TODO: use an interface to pass the user choice back to the activity
                        }
                    })
                    .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            MyDialogFragment.this.getDialog().cancel();
                        }
                    });
            return builder.create();
        }
    
        @Override
        public void onResume() {
            super.onResume();
    
            // disable positive button by default
            AlertDialog dialog = (AlertDialog) getDialog();
            dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
        }
    }
    

    The custom dialog can be run from an activity like this:

    MyDialogFragment dialog = new MyDialogFragment();
    dialog.show(getFragmentManager(), "MyTag");
    

    Notes

    • For the sake of brevity, I omitted the communication interface to pass the user choice info back to the activity. The documentation shows how this is done, though.
    • The button is still null in onCreateDialog so I disabled it in onResume. This has the undesireable effect of disabling the it again if the user switches to another app and then comes back without dismissing the dialog. This could be solved by also unselecting any user choices or by calling a Runnable from onCreateDialog to disable the button on the next run loop.

      view.post(new Runnable() {
          @Override
          public void run() {
              AlertDialog dialog = (AlertDialog) getDialog();
              dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
          }
      });
      

    Related

    • Android Alert Dialog with one, two, and three buttons
    • How can I display a list view in an Android Alert Dialog?
    0 讨论(0)
  • 2020-11-22 00:29

    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.

    0 讨论(0)
提交回复
热议问题