首页 文章

单击按钮时如何防止对话框关闭

提问于
浏览
637

我有一个带有 EditText 的对话框用于输入 . 当我单击对话框上的"yes"按钮时,它将验证输入,然后关闭对话框 . 但是,如果输入错误,我想保持在同一个对话框中 . 每次无论输入是什么,当我单击"no"按钮时,对话框应自动关闭 . 我怎么能禁用它?顺便说一句,我已经使用PositiveButton和NegativeButton作为对话框上的按钮 .

18 回答

  • 6

    受Tom的回答启发,我相信这里的想法是:

    • 在创建对话框期间将 onClickListener 设置为 null

    • 然后在显示对话框后设置 onClickListener .

    您可以像Tom一样覆盖 onShowListener . 或者,你可以

    • 在调用AlertDialog的 show() 后获取按钮

    • 设置按钮' onClickListener 如下(我认为稍微可读) .

    码:

    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);
        }
    });
    
  • 26

    把它放在你的Utility类中 .

    /*
         * Show Dialog with Title, Message, Button1, Button2 with Button1 and Button2 Listener
         */
        public AlertDialog showDialog(Context ctx, String title, String msg,
                                      String btn1, String btn2,
                                      OnClickListener listener1,
                                      OnClickListener listener2) {
    
            AlertDialog.Builder builder = new AlertDialog.Builder(ctx)
                    .setTitle(title)
                    .setMessage(msg)
                    .setCancelable(true)
                    .setPositiveButton(btn1, listener1);
            if (btn2 != null)
                builder.setNegativeButton(btn2, listener2);
    
            AlertDialog alert = builder.create();
            return alert;
        }
    

    然后当你需要显示对话框时

    showDialog(getActivity(), "Title", "Message", "First button title", "Second button title",
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                dialog.dismiss();
                                // TODO: 5/14/2018 first button clicked 
                            }
                        },
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                dialog.dismiss();
                                // TODO: 5/14/2018 second button clicked
                            }
                        }).show();
    
  • 32

    EDIT: 这仅适用于API 8,如某些评论所述 .

    这是一个迟到的答案,但您可以将一个onShowListener添加到AlertDialog,然后您可以覆盖该按钮的onClickListener .

    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();
    
  • 8

    如果你正在使用 DialogFragment ,这就是一些东西 - 无论如何这是处理Dialogs的推荐方法 .

    AlertDialog的 setButton() 方法会发生什么(我想象 AlertDialogBuildersetPositiveButton()setNegativeButton() 也一样)是你设置的按钮(例如 AlertDialog.BUTTON_POSITIVE )在按下时实际上会触发两个不同的 OnClickListener 对象 .

    第一个是DialogInterface.OnClickListener,它是 setButton()setPositiveButton()setNegativeButton() 的参数 .

    另一个是View.OnClickListener,它将设置为在按下任何按钮时自动关闭 AlertDialog - 并由 AlertDialog 本身设置 .

    你可以做的是使用 setButton()null 作为 DialogInterface.OnClickListener ,创建按钮,然后在 View.OnClickListener 中调用自定义操作方法 . 例如,

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState)
    {
        AlertDialog alertDialog = new AlertDialog(getActivity());
        // set more items...
        alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, "OK", null);
    
        return alertDialog;
    }
    

    然后,您可以覆盖 DialogFragmentonResume() 方法中的默认值 AlertDialog 's buttons' View.OnClickListener (否则将关闭对话框):

    @Override
    public void onResume()
    {
        super.onResume();
        AlertDialog alertDialog = (AlertDialog) getDialog();
        Button okButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
        okButton.setOnClickListener(new View.OnClickListener() { 
            @Override
            public void onClick(View v)
            {
                performOkButtonAction();
            }
        });
    }
    
    private void performOkButtonAction() {
        // Do your stuff here
    }
    

    您需要在 onResume() 方法中设置它,因为 getButton() 将返回 null ,直到显示对话框为止!

    这应该导致您的自定义操作方法只被调用一次,默认情况下不会解除对话框 .

  • 2
    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));
        }
    }
    }
    
  • 4

    它可以用最简单的方式构建:

    带有 Custom Viewtwo Buttons (正面和负面)的警报对话框 .

    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()).setTitle(getString(R.string.select_period));
    builder.setPositiveButton(getString(R.string.ok), null);
    
     builder.setNegativeButton(getString(R.string.cancel), new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
    
        // Click of Cancel Button
    
       }
     });
    
      LayoutInflater li = LayoutInflater.from(getActivity());
      View promptsView = li.inflate(R.layout.dialog_date_picker, null, false);
      builder.setView(promptsView);
    
      DatePicker startDatePicker = (DatePicker)promptsView.findViewById(R.id.startDatePicker);
      DatePicker endDatePicker = (DatePicker)promptsView.findViewById(R.id.endDatePicker);
    
      final AlertDialog alertDialog = builder.create();
      alertDialog.show();
    
      Button theButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
      theButton.setOnClickListener(new CustomListener(alertDialog, startDatePicker, endDatePicker));
    

    CustomClickLister of Android Alert Dialog with one, two, and three buttons of Alert Dailog

    private class CustomListener implements View.OnClickListener {
            private final Dialog dialog;
            private DatePicker mStartDp, mEndDp;
        public CustomListener(Dialog dialog, DatePicker dS, DatePicker dE) {
            this.dialog = dialog;
            mStartDp = dS;
            mEndDp = dE;
        }
    
        @Override
        public void onClick(View v) {
    
            int day1  = mStartDp.getDayOfMonth();
            int month1= mStartDp.getMonth();
            int year1 = mStartDp.getYear();
            Calendar cal1 = Calendar.getInstance();
            cal1.set(Calendar.YEAR, year1);
            cal1.set(Calendar.MONTH, month1);
            cal1.set(Calendar.DAY_OF_MONTH, day1);
    
    
            int day2  = mEndDp.getDayOfMonth();
            int month2= mEndDp.getMonth();
            int year2 = mEndDp.getYear();
            Calendar cal2 = Calendar.getInstance();
            cal2.set(Calendar.YEAR, year2);
            cal2.set(Calendar.MONTH, month2);
            cal2.set(Calendar.DAY_OF_MONTH, day2);
    
            if(cal2.getTimeInMillis()>=cal1.getTimeInMillis()){
                dialog.dismiss();
                Log.i("Dialog", "Dismiss");
                // Condition is satisfied so do dialog dismiss
                }else {
                Log.i("Dialog", "Do not Dismiss");
                // Condition is not satisfied so do not dialog dismiss
            }
    
        }
    }
    

    Done

  • 3

    这可能是非常晚的回复,但使用setCancelable可以解决问题 .

    alertDial.setCancelable(false);
    
  • 3

    For ProgressDialogs

    要防止对话框自动被关闭,您必须在显示 ProgressDialog 之后设置 OnClickListener ,如下所示:

    connectingDialog = new ProgressDialog(this);
    
    connectingDialog.setCancelable(false);
    connectingDialog.setCanceledOnTouchOutside(false);
    
    // Create the button but set the listener to a null object.
    connectingDialog.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel", 
            (DialogInterface.OnClickListener) null )
    
    // Show the dialog so we can then get the button from the view.
    connectingDialog.show();
    
    // Get the button from the view.
    Button dialogButton = connectingDialog.getButton( DialogInterface.BUTTON_NEGATIVE);
    
    // Set the onClickListener here, in the view.
    dialogButton.setOnClickListener( new View.OnClickListener() {
    
        @Override
        public void onClick ( View v ) {
    
            // Dialog will not get dismissed until you call dismiss() explicitly.
    
        }
    
    });
    
  • 0

    To prevent Dialog box from closing when clicked and it should only close when internet is available

    我正在尝试做同样的事情,因为我不希望关闭对话框,除非连接互联网 .

    这是我的代码

    AlertDialog.Builder builder=new AlertDialog.Builder(MainActivity.this); builder.setTitle("Internet Not Connected");
        if(ifConnected()){
    
            Toast.makeText(this, "Connected or not", Toast.LENGTH_LONG).show();
        }
        else{
            builder.setPositiveButton("Retry", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                   if(!ifConnected())
                   {
                       builder.show();
                   }
                }
            }).setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    finish();
                }
            });
            builder.show();
    
        }
    

    这是我的连接管理器代码

    private boolean ifConnected()
    {
        ConnectivityManager connectivityManager= (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo=connectivityManager.getActiveNetworkInfo();
       return networkInfo!=null && networkInfo.isConnected();
    }
    
  • 22

    我编写了一个简单的类(AlertDialogBuilder),您可以使用它来在按对话框的按钮时禁用自动关闭功能 .

    它也与Android 1.6兼容,因此它不使用OnShowListener(只有API> = 8) .

    因此,您可以使用此CustomAlertDialogBuilder,而不是使用AlertDialog.Builder . 最重要的部分是你不应该调用 create() ,而应该只调用 show() 方法 . 我添加了setCanceledOnTouchOutside()和setOnDismissListener等方法,以便您仍然可以直接在构建器上设置它们 .

    我在Android 1.6,2.x,3.x和4.x上进行了测试,所以它应该可以正常工作 . 如果您发现一些问题,请在此处评论 .

    package com.droidahead.lib.utils;
    
    import android.app.AlertDialog;
    import android.content.Context;
    import android.content.DialogInterface;
    import android.view.View;
    import android.view.View.OnClickListener;
    
    public class CustomAlertDialogBuilder extends AlertDialog.Builder {
        /**
         * Click listeners
         */
        private DialogInterface.OnClickListener mPositiveButtonListener = null;
        private DialogInterface.OnClickListener mNegativeButtonListener = null;
        private DialogInterface.OnClickListener mNeutralButtonListener = null;
    
        /**
         * Buttons text
         */
        private CharSequence mPositiveButtonText = null;
        private CharSequence mNegativeButtonText = null;
        private CharSequence mNeutralButtonText = null;
    
        private DialogInterface.OnDismissListener mOnDismissListener = null;
    
        private Boolean mCancelOnTouchOutside = null;
    
        public CustomAlertDialogBuilder(Context context) {
            super(context);
        }
    
        public CustomAlertDialogBuilder setOnDismissListener (DialogInterface.OnDismissListener listener) {
            mOnDismissListener = listener;
            return this;
        }
    
        @Override
        public CustomAlertDialogBuilder setNegativeButton(CharSequence text, DialogInterface.OnClickListener listener) {
            mNegativeButtonListener = listener;
            mNegativeButtonText = text;
            return this;
        }
    
        @Override
        public CustomAlertDialogBuilder setNeutralButton(CharSequence text, DialogInterface.OnClickListener listener) {
            mNeutralButtonListener = listener;
            mNeutralButtonText = text;
            return this;
        }
    
        @Override
        public CustomAlertDialogBuilder setPositiveButton(CharSequence text, DialogInterface.OnClickListener listener) {
            mPositiveButtonListener = listener;
            mPositiveButtonText = text;
            return this;
        }
    
        @Override
        public CustomAlertDialogBuilder setNegativeButton(int textId, DialogInterface.OnClickListener listener) {
            setNegativeButton(getContext().getString(textId), listener);
            return this;
        }
    
        @Override
        public CustomAlertDialogBuilder setNeutralButton(int textId, DialogInterface.OnClickListener listener) {
            setNeutralButton(getContext().getString(textId), listener);
            return this;
        }
    
        @Override
        public CustomAlertDialogBuilder setPositiveButton(int textId, DialogInterface.OnClickListener listener) {
            setPositiveButton(getContext().getString(textId), listener);
            return this;
        }
    
        public CustomAlertDialogBuilder setCanceledOnTouchOutside (boolean cancelOnTouchOutside) {
            mCancelOnTouchOutside = cancelOnTouchOutside;
            return this;
        }
    
    
    
        @Override
        public AlertDialog create() {
            throw new UnsupportedOperationException("CustomAlertDialogBuilder.create(): use show() instead..");
        }
    
        @Override
        public AlertDialog show() {
            final AlertDialog alertDialog = super.create();
    
            DialogInterface.OnClickListener emptyOnClickListener = new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) { }
            };
    
    
            // Enable buttons (needed for Android 1.6) - otherwise later getButton() returns null
            if (mPositiveButtonText != null) {
                alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, mPositiveButtonText, emptyOnClickListener);
            }
    
            if (mNegativeButtonText != null) {
                alertDialog.setButton(AlertDialog.BUTTON_NEGATIVE, mNegativeButtonText, emptyOnClickListener);
            }
    
            if (mNeutralButtonText != null) {
                alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, mNeutralButtonText, emptyOnClickListener);
            }
    
            // Set OnDismissListener if available
            if (mOnDismissListener != null) {
                alertDialog.setOnDismissListener(mOnDismissListener);
            }
    
            if (mCancelOnTouchOutside != null) {
                alertDialog.setCanceledOnTouchOutside(mCancelOnTouchOutside);
            }
    
            alertDialog.show();
    
            // Set the OnClickListener directly on the Button object, avoiding the auto-dismiss feature
            // IMPORTANT: this must be after alert.show(), otherwise the button doesn't exist..
            // If the listeners are null don't do anything so that they will still dismiss the dialog when clicked
            if (mPositiveButtonListener != null) {
                alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new OnClickListener() {
    
                    @Override
                    public void onClick(View v) {
                        mPositiveButtonListener.onClick(alertDialog, AlertDialog.BUTTON_POSITIVE);
                    }
                });
            }
    
            if (mNegativeButtonListener != null) {
                alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE).setOnClickListener(new OnClickListener() {
    
                    @Override
                    public void onClick(View v) {
                        mNegativeButtonListener.onClick(alertDialog, AlertDialog.BUTTON_NEGATIVE);
                    }
                });
            }
    
            if (mNeutralButtonListener != null) {
                alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener(new OnClickListener() {
    
                    @Override
                    public void onClick(View v) {
                        mNeutralButtonListener.onClick(alertDialog, AlertDialog.BUTTON_NEUTRAL);
                    }
                });
            }
    
            return alertDialog;
        }   
    }
    

    EDIT 这是一个关于如何使用CustomAlertDialogBuilder的小例子:

    // Create the CustomAlertDialogBuilder
    CustomAlertDialogBuilder dialogBuilder = new CustomAlertDialogBuilder(context);
    
    // Set the usual data, as you would do with AlertDialog.Builder
    dialogBuilder.setIcon(R.drawable.icon);
    dialogBuilder.setTitle("Dialog title");
    dialogBuilder.setMessage("Some text..");
    
    // Set your buttons OnClickListeners
    dialogBuilder.setPositiveButton ("Button 1", new DialogInterface.OnClickListener() {
        public void onClick (DialogInterface dialog, int which) {
            // Do something...
    
            // Dialog will not dismiss when the button is clicked
            // call dialog.dismiss() to actually dismiss it.
        }
    });
    
    // By passing null as the OnClickListener the dialog will dismiss when the button is clicked.               
    dialogBuilder.setNegativeButton ("Close", null);
    
    // Set the OnDismissListener (if you need it)       
    dialogBuilder.setOnDismissListener(new DialogInterface.OnDismissListener() {
        public void onDismiss(DialogInterface dialog) {
            // dialog was just dismissed..
        }
    });
    
    // (optional) set whether to dismiss dialog when touching outside
    dialogBuilder.setCanceledOnTouchOutside(false);
    
    // Show the dialog
    dialogBuilder.show();
    

    干杯,

    Yuvi

  • 2

    对于API 8之前,我使用布尔标志,解除侦听器和调用dialog.show解决了问题,如果editText的内容不正确的话 . 像这样:

    case ADD_CLIENT:
            LayoutInflater factoryClient = LayoutInflater.from(this);
            final View EntryViewClient = factoryClient.inflate(
                    R.layout.alert_dialog_add_client, null);
    
            EditText ClientText = (EditText) EntryViewClient
                    .findViewById(R.id.client_edit);
    
            AlertDialog.Builder builderClient = new AlertDialog.Builder(this);
            builderClient
                    .setTitle(R.string.alert_dialog_client)
                    .setCancelable(false)
                    .setView(EntryViewClient)
                    .setPositiveButton("Save",
                            new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog,
                                        int whichButton) {
                                    EditText newClient = (EditText) EntryViewClient
                                            .findViewById(R.id.client_edit);
                                    String newClientString = newClient
                                            .getText().toString();
                                    if (checkForEmptyFields(newClientString)) {
                                        //If field is empty show toast and set error flag to true;
                                        Toast.makeText(getApplicationContext(),
                                                "Fields cant be empty",
                                                Toast.LENGTH_SHORT).show();
                                        add_client_error = true;
                                    } else {
                                        //Here save the info and set the error flag to false
                                        add_client_error = false;
                                    }
                                }
                            })
                    .setNegativeButton("Cancel",
                            new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog,
                                        int id) {
                                    add_client_error = false;
                                    dialog.cancel();
                                }
                            });
            final AlertDialog alertClient = builderClient.create();
            alertClient.show();
    
            alertClient
                    .setOnDismissListener(new DialogInterface.OnDismissListener() {
    
                        @Override
                        public void onDismiss(DialogInterface dialog) {
                            //If the error flag was set to true then show the dialog again
                            if (add_client_error == true) {
                                alertClient.show();
                            } else {
                                return;
                            }
    
                        }
                    });
            return true;
    
  • 0

    我的解决方案很简单,只需为您的DialogFragment使用自定义布局,并在您的内容下添加一个LinearLayout,可以设置为无边框以匹配Google Material Design,然后找到新创建的按钮并覆盖它们的OnClickListener:DialogFragment.java代码:

    public class AddTopicFragment extends DialogFragment {
        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
            // Get the layout inflater
            LayoutInflater inflater = getActivity().getLayoutInflater();
            final View dialogView = inflater.inflate(R.layout.dialog_add_topic, null);
    
            Button saveTopicDialogButton = (Button) dialogView.findViewById(R.id.saveTopicDialogButton);
            Button cancelSaveTopicDialogButton = (Button) dialogView.findViewById(R.id.cancelSaveTopicDialogButton);
    
            final AppCompatEditText addTopicNameET = (AppCompatEditText) dialogView.findViewById(R.id.addTopicNameET);
            final AppCompatEditText addTopicCreatedByET = (AppCompatEditText) dialogView.findViewById(R.id.addTopicCreatedByET);
    
            saveTopicDialogButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    // validate inputs
                    if(addTopicNameET.getText().toString().trim().isEmpty()){
                        addTopicNameET.setError("Topic name can't be empty");
                        addTopicNameET.requestFocus();
                    }else if(addTopicCreatedByET.getText().toString().trim().isEmpty()){
                        addTopicCreatedByET.setError("Topic created by can't be empty");
                        addTopicCreatedByET.requestFocus();
                    }else {
                        // save topic to database
                        Topic topic = new Topic();
                        topic.name = addTopicNameET.getText().toString().trim();
                        topic.createdBy = addTopicCreatedByET.getText().toString().trim();
                        topic.createdDate = new Date().getTime();
                        topic.save();
                        AddTopicFragment.this.dismiss();
                    }
                }
            });
            cancelSaveTopicDialogButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    AddTopicFragment.this.dismiss();
                }
            });
            // Inflate and set the layout for the dialog
            // Pass null as the parent view because its going in the dialog layout
            builder.setView(dialogView)
                    .setMessage(getString(R.string.add_topic_message));
            return builder.create();
        }
    
    
    }
    

    dialog_add_topic.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:orientation="vertical"
        android:padding="@dimen/activity_horizontal_margin"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <android.support.design.widget.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:errorEnabled="true">
    
            <android.support.v7.widget.AppCompatEditText
                android:id="@+id/addTopicNameET"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Topic Name"
                android:inputType="textPersonName"
                android:maxLines="1" />
    
        </android.support.design.widget.TextInputLayout>
    
        <android.support.design.widget.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:errorEnabled="true">
    
            <android.support.v7.widget.AppCompatEditText
                android:id="@+id/addTopicCreatedByET"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Created By"
                android:inputType="textPersonName"
                android:maxLines="1" />
    
        </android.support.design.widget.TextInputLayout>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <Button
                android:text="@string/cancel"
                android:layout_weight="1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/cancelSaveTopicDialogButton"
                style="@style/Widget.AppCompat.Button.ButtonBar.AlertDialog" />
    
            <Button
                android:text="@string/save"
                android:layout_weight="1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/saveTopicDialogButton"
                style="@style/Widget.AppCompat.Button.ButtonBar.AlertDialog" />
    
        </LinearLayout>
    
    
    </LinearLayout>
    

    This is the final result:

  • 820

    以下是针对所有类型对话框的一些解决方案,包括适用于所有API级别的AlertDialog.Builder解决方案(在API 8下工作,其他答案在此处没有) . AlertDialogs有使用AlertDialog.Builder,DialogFragment和DialogPreference的解决方案 .

    下面是代码示例,演示如何覆盖默认的公共按钮处理程序,并防止对话框关闭这些不同形式的对话框 . 所有示例都显示了如何防止正面按钮关闭对话框 .

    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 - 在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 - 覆盖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 - 覆盖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.
                    }
                });
    }
    

    方法说明:

    通过Android源代码查看AlertDialog默认实现的工作原理是为OnCreate()中的所有实际按钮注册一个公共按钮处理程序 . 当单击一个按钮时,公共按钮处理程序将click事件转发到您在setButton()中传递的任何处理程序,然后调用解除对话框 . 如果您希望在按下其中一个按钮时阻止关闭对话框,则必须替换按钮实际视图的公共按钮处理程序 . 因为它是在OnCreate()中分配的,所以必须在调用默认的OnCreate()实现后替换它 . 在show()方法的过程中调用OnCreate . 您可以创建一个自定义Dialog类并重写OnCreate()以调用super.OnCreate()然后覆盖按钮处理程序,但是如果您创建一个自定义对话框,则不会免费获得Builder,在这种情况下,有什么意义?因此,在按照设计的方式使用对话框但在解除它时进行控制时,一种方法是首先调用dialog.Show(),然后使用dialog.getButton()获取对按钮的引用以覆盖单击处理程序 . 另一种方法是使用setOnShowListener()并实现查找按钮视图并替换OnShowListener中的处理程序 . 两者之间的功能差异是“差不多”,这取决于最初创建对话框实例的线程 . 查看源代码,onShowListener将被发布到在创建该对话框的线程上运行的处理程序的消息调用 . 因此,由于您的OnShowListener是由消息队列上发布的消息调用的,因此技术上可能在show完成后调用您的侦听器一段时间 . 因此,我认为最安全的方法是第一种:调用show.Dialog(),然后立即在同一个执行路径中替换按钮处理程序 . 由于您调用show()的代码将在主GUI线程上运行,这意味着您执行的任何代码show()将在该线程上的任何其他代码之前执行,而OnShowListener方法的时序由于消息队列 .

  • 17

    this link的答案是一个简单的解决方案,它可以直接与API 3兼容 . 它与Tom Bollwitt的解决方案非常相似,但不使用兼容性较差的OnShowListener .

    是的,你可以 . 您基本上需要:使用DialogBuilder创建对话框show()对话框在显示的对话框中查找按钮并覆盖它们的onClickListener

    自从我扩展EditTextPreference以来,我对Kamen的代码做了一些小修改 .

    @Override
    protected void showDialog(Bundle state) {
      super.showDialog(state);
    
      class mocl implements OnClickListener{
        private final AlertDialog dialog;
        public mocl(AlertDialog dialog) {
              this.dialog = dialog;
          }
        @Override
        public void onClick(View v) {
    
            //checks if EditText is empty, and if so tells the user via Toast
            //otherwise it closes dialog and calls the EditTextPreference's onClick
            //method to let it know that the button has been pressed
    
            if (!IntPreference.this.getEditText().getText().toString().equals("")){
            dialog.dismiss();
            IntPreference.this.onClick(dialog,DialogInterface.BUTTON_POSITIVE);
            }
            else {
                Toast t = Toast.makeText(getContext(), "Enter a number!", Toast.LENGTH_SHORT);
                t.show();
            }
    
        }
      }
    
      AlertDialog d = (AlertDialog) getDialog();
      Button b = d.getButton(DialogInterface.BUTTON_POSITIVE);
      b.setOnClickListener(new mocl((d)));
    }
    

    好好玩!

  • 591

    你可以添加builder.show();在返回之前验证消息;

    像这样

    public void login()
    {
        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setView(R.layout.login_layout);
        builder.setTitle("Login");
    
    
    
        builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener()
        {
            @Override
            public void onClick(DialogInterface dialog, int id)
            {
                dialog.cancel();
            }
        });// put the negative button before the positive button, so it will appear
    
        builder.setPositiveButton("Ok", new DialogInterface.OnClickListener()
        {
            @Override
            public void onClick(DialogInterface dialog, int id)
            {
                Dialog d = (Dialog) dialog;
                final EditText etUserName = (EditText) d.findViewById(R.id.etLoginName);
                final EditText etPassword = (EditText) d.findViewById(R.id.etLoginPassword);
                String userName = etUserName.getText().toString().trim();
                String password = etPassword.getText().toString().trim();
    
                if (userName.isEmpty() || password.isEmpty())
                {
    
                    Toast.makeText(getApplicationContext(),
                            "Please Fill all fields", Toast.LENGTH_SHORT).show();
                    builder.show();// here after validation message before retrun
                                   //  it will reopen the dialog
                                  // till the user enter the right condition
                    return;
                }
    
                user = Manager.get(getApplicationContext()).getUserByName(userName);
    
                if (user == null)
                {
                    Toast.makeText(getApplicationContext(),
                            "Error ethier username or password are wrong", Toast.LENGTH_SHORT).show();
                    builder.show();
                    return;
                }
                if (password.equals(user.getPassword()))
                {
                    etPassword.setText("");
                    etUserName.setText("");
                    setLogged(1);
                    setLoggedId(user.getUserId());
                    Toast.makeText(getApplicationContext(),
                            "Successfully logged in", Toast.LENGTH_SHORT).show();
                   dialog.dismiss();// if every thing is ok then dismiss the dialog
                }
                else
                {
                    Toast.makeText(getApplicationContext(),
                            "Error ethier username or password are wrong", Toast.LENGTH_SHORT).show();
                    builder.show();
                    return;
                }
    
            }
        });
    
        builder.show();
    
    }
    
  • 3

    另一种解决方案

    我想从UX的角度提出另一个答案 .

    为什么要在单击按钮时阻止对话框关闭?大概是因为你有一个自定义对话框,用户没有做出选择或尚未完全填满所有内容 . 如果它们没有完成,那么你不应该让它们完全点击肯定按钮 . 只需禁用它,直到一切准备就绪 .

    这里的其他答案提供了许多技巧来覆盖正面按钮点击 . 如果这很重要,Android会不会做出方便的方法呢?他们没有 .

    相反,Dialogs design guide显示了这种情况的一个例子 . 在用户做出选择之前,“确定”按钮被禁用 . 根本不需要压倒一切的技巧 . 对用户来说显而易见的是,在继续之前仍需要做一些事情 .

    如何禁用正按钮

    Android documentation for creating a custom dialog layout . 它建议您将 AlertDialog 放在 DialogFragment 内 . 然后,您需要做的就是在布局元素上设置侦听器,以了解何时启用或禁用正按钮 .

    正面按钮可以像这样禁用:

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

    这是一个完整的工作 DialogFragment ,带有禁用的正按钮,例如可能在上图中使用 .

    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);
        }
    }
    

    可以从以下活动运行自定义对话框:

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

    Notes

    • 为了简洁起见,我省略了通信接口以将用户选择信息传递回活动 . 但是,documentation显示了这是如何完成的 .

    • onCreateDialog 中的按钮仍然是 null 所以我在 onResume 中禁用了它 . 如果用户切换到另一个,则具有不希望的再次禁用它的效果应用程序,然后回来而不解除对话框 . 这可以通过取消选择任何用户选择或通过从 onCreateDialog 调用 Runnable 来禁用下一个运行循环上的按钮来解决 .

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

    相关

  • 0

    这段代码对你有用,因为我有一个类似的问题,这对我有用 . :)

    1-覆盖片段对话框类中的Onstart()方法 .

    @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

    如果您正在使用 material design ,我建议您查看material-dialogs . 它为我解决了与当前打开的Android错误相关的几个问题(请参阅78088),但 most importantly for this ticket 它有一个 autoDismiss 标志,可以在使用 Builder 时设置 .

相关问题