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

后端 未结 18 2171
无人及你
无人及你 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: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?

提交回复
热议问题