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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2620444/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 06:37:47  来源:igfitidea点击:

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

androiddialogandroid-alertdialogandroid-dialogandroid-dialogfragment

提问by user304881

I have a dialog with EditTextfor 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.

我有一个EditText用于输入的对话框。当我单击对话框上的“是”按钮时,它将验证输入然后关闭对话框。但是,如果输入错误,我想保持在同一个对话框中。每次无论输入是什么,当我单击“否”按钮时,对话框都应该自动关闭。我怎样才能禁用它?顺便说一下,我已经将 PositiveButton 和 NegativeButton 用于对话框上的按钮。

回答by Tom Bollwitt

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

编辑:如某些评论所述,这仅适用于 API 8+。

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

这是一个迟到的答案,但您可以向 AlertDialog 添加一个 onShowListener,然后您可以在其中覆盖按钮的 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();

回答by Sogger

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.

以下是适用于所有类型对话框的一些解决方案,包括适用于所有 API 级别的 AlertDialog.Builder 解决方案(适用于 API 8,此处的另一个答案不适用)。有使用 AlertDialog.Builder、DialogFragment 和 DialogPreference 的 AlertDialogs 解决方案。

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

注意:对于那些想要了解更多细节的人,在示例之后描述了对话框关闭如何在底层 android 类中工作,以及为什么选择以下方法



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

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 - override onResume()

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 - override showDialog()

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

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.

查看 Android 源代码,AlertDialog 默认实现通过向 OnCreate() 中的所有实际按钮注册一个公共按钮处理程序来工作。单击按钮时,公共按钮处理程序将单击事件转发到您在 setButton() 中传递的任何处理程序,然后调用关闭对话框。

如果您希望在按下这些按钮之一时阻止对话框关闭,则必须替换按钮实际视图的公共按钮处理程序。因为它是在 OnCreate() 中分配的,所以必须在调用默认的 OnCreate() 实现后替换它。OnCreate 在 show() 方法的过程中被调用。您可以创建一个自定义 Dialog 类并覆盖 OnCreate() 以调用 super.OnCreate() 然后覆盖按钮处理程序,但是如果您创建一个自定义对话框,您将无法免费获得 Builder,在这种情况下有什么意义?

因此,按照设计的方式使用对话框但控制何时关闭,一种方法是首先调用 dialog.Show(),然后使用 dialog.getButton() 获取对按钮的引用以覆盖单击处理程序。另一种方法是使用 setOnShowListener() 并实现查找按钮视图并替换 OnShowListener 中的处理程序。两者之间的功能差异“几乎”为零,具体取决于最初创建对话框实例的线程。查看源代码,onShowListener 被一条消息调用,该消息发布到在创建该对话框的线程上运行的处理程序。因此,由于您的 OnShowListener 被发布在消息队列上的消息调用,从技术上讲,在显示完成后调用您的侦听器可能会延迟一段时间。

因此,我认为最安全的方法是第一种:调用 show.Dialog(),然后立即在同一执行路径中替换按钮处理程序。由于您调用 show() 的代码将在主 GUI 线程上运行,这意味着您跟随 show() 的任何代码都将在该线程上的任何其他代码之前执行,而 OnShowListener 方法的时间受制于消息队列。

回答by Suragch

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.

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

Instead, the Dialogs design guideshows 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.

相反,Dialogs 设计指南显示了这种情况的示例。在用户做出选择之前,确定按钮被禁用。根本不需要压倒一切的技巧。对于用户来说很明显在继续之前仍然需要做一些事情。

enter image description here

在此处输入图片说明

How to disable the positive button

如何禁用正按钮

See the Android documentation for creating a custom dialog layout. It recommends that you place your AlertDialoginside 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.

请参阅Android 文档以创建自定义对话框布局。它建议您将您的AlertDialog内部文件放在DialogFragment. 然后您需要做的就是在布局元素上设置侦听器以了解何时启用或禁用正按钮。

The positive button can be disabled like this:

可以像这样禁用正按钮:

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

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

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

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 documentationshows how this is done, though.
  • The button is still nullin onCreateDialogso 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 Runnablefrom onCreateDialogto 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);
        }
    });
    
  • 为简洁起见,我省略了将用户选择信息传递回活动的通信接口。不过,文档显示了这是如何完成的。
  • 该按钮仍在nullonCreateDialog所以我在onResume. 如果用户切换到另一个应用程序然后在没有关闭对话框的情况下返回,这会产生不利的效果,即再次禁用它。这也可以通过取消选择任何用户选择或通过调用RunnablefromonCreateDialog在下一个运行循环中禁用按钮来解决。

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

Related

有关的

回答by YuviDroid

I've written a simple class (an AlertDialogBuilder) that you can use to disable the auto-dismiss feature when pressing the dialog's buttons.

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

It is compatible also with Android 1.6, so it doesn't make use of the OnShowListener (which is available only API >= 8).

它也与 Android 1.6 兼容,因此它不使用 OnShowListener(仅 API >= 8 可用)。

So, instead of using AlertDialog.Builder you can use this CustomAlertDialogBuilder. The most important part is that you should not call create(), but only the show()method. I've added methods like setCanceledOnTouchOutside()and setOnDismissListenerso that you can still set them directly on the builder.

因此,您可以使用此 CustomAlertDialogBu​​ilder,而不是使用 AlertDialog.Builder。最重要的部分是您不应调用create(),而应调用show()方法。我添加了像setCanceledOnTouchOutside()setOnDismissListener这样的方法,这样你仍然可以直接在构建器上设置它们。

I tested it on Android 1.6, 2.x, 3.x and 4.x so it should work pretty well. If you find some problems please comment here.

我在 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;
    }   
}

EDITHere is a small example on how to use the CustomAlertDialogBuilder:

编辑这是一个关于如何使用 CustomAlertDialogBu​​ilder 的小例子:

// 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();

Cheers,

干杯,

Yuvi

尤维

回答by Zhuiguang Liu

Here's something if you are using DialogFragment- which is the recommended way to handle Dialogs anyway.

如果您正在使用DialogFragment,这里有一些东西- 无论如何,这是处理对话框的推荐方法。

What happens with AlertDialog's setButton()method (and I imagine the same with AlertDialogBuilder's setPositiveButton()and setNegativeButton()) is that the button you set (e.g. AlertDialog.BUTTON_POSITIVE) with it will actually trigger TWO different OnClickListenerobjects when pressed.

AlertDialog 的setButton()方法会发生什么(我想AlertDialogBuilder'ssetPositiveButton()和's和's和's一样setNegativeButton())是您设置的按钮(例如AlertDialog.BUTTON_POSITIVEOnClickListener在按下时实际上会触发两个不同的对象。

The first being DialogInterface.OnClickListener, which is a parameter to setButton(), setPositiveButton(), and setNegativeButton().

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

The other is View.OnClickListener, which will be set to automatically dismiss your AlertDialogwhen any of its button is pressed - and is set by AlertDialogitself.

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

What you can do is to use setButton()with nullas the DialogInterface.OnClickListener, to create the button, and then call your custom action method inside View.OnClickListener. For example,

您可以做的是使用setButton()withnull作为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;
}

Then, you may override the default AlertDialog's buttons' View.OnClickListener(which would otherwise dismiss the dialog) in the DialogFragment's onResume()method:

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

@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
}

You will need to set this in the onResume()method because getButton()will return nulluntil after the dialog has been shown!

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

This should cause your custom action method to only be called once, and the dialog won't be dismissed by default.

这应该会导致您的自定义操作方法仅被调用一次,并且默认情况下不会关闭对话框。

回答by ericn

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

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

  • Set the onClickListenerduring the creation of the dialog to null
  • Then set a onClickListenerafter the dialog is shown.
  • onClickListener在对话框的创建过程中设置为null
  • 然后onClickListener在显示对话框后设置 a 。

You can override the onShowListenerlike Tom. Alternatively, you can

你可以覆盖onShowListener像汤姆。或者,您可以

  1. get the button after calling AlertDialog's show()
  2. set the buttons' onClickListeneras follows (slightly more readable I think).
  1. 调用 AlertDialog 后获取按钮 show()
  2. onClickListener按如下方式设置按钮(我认为可读性更高)。

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

回答by Steve

For pre API 8 i solved the problem using a boolean flag, a dismiss listener and calling dialog.show again if in case the content of the editText wasn′t correct. Like this:

对于 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;

回答by lukeuser

The answer at this linkis a simple solution, and which is compatible right back to API 3. It is very similiar to Tom Bollwitt's solution, but without using the less compatible OnShowListener.

这个链接的答案是一个简单的解决方案,它与 API 3 兼容。它与 Tom Bollwitt 的解决方案非常相似,但不使用兼容性较差的 OnShowListener。

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

是的你可以。你基本上需要:

  1. 使用 DialogBu​​ilder 创建对话框
  2. show() 对话框
  3. 在显示的对话框中找到按钮并覆盖它们的 onClickListener

I made minor adaptions to Kamen's code since I was extending an EditTextPreference.

自从我扩展了 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)));
}

Such fun!

好好玩!

回答by Luis Nu?ez

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.

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

回答by Joshua Pinter

For ProgressDialogs

对于 ProgressDialogs

To prevent the dialog from being dismissed automatically you have to set the OnClickListenerafter the ProgressDialogis shown, like so:

为了防止对话框自动关闭,您必须OnClickListenerProgressDialog显示后设置,如下所示:

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.

    }

});