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

814

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

21个回答

1011

编辑: 如一些评论所述,此方法只适用于API 8及以上。

虽然这是一个晚答案,但您可以将onShowListener添加到AlertDialog中,在那里可以重写按钮的onClickLister。

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
好的,晚到总比没有好,我正需要这个,谢谢,+1 :) 这是一种优雅的方式来为你的对话框添加验证,特别是当你已经有一个处理警报的包装类时。 - Guillaume
12
无效。AlertDialog.Builder.setOnShowListener不存在。 http://developer.android.com/reference/android/app/AlertDialog.Builder.html - Leandros
4
在 API 8 之前,你可以调用 d.getButton(AlertDialog.BUTTON_POSITIVE) 这个公开方法,但是必须在调用 show() 方法后才能使用它,否则会返回 null。 - Hurda
14
您可以通过在对话框构建器中设置空OnClickListener来使其更加简洁(这样可以节省空的“//this will be overridden”侦听器)。 - Steve Haley
2
@Leandros setOnShowListenerDialog 的方法,而不是 Dialog.Builder 的方法,或者你可能在参考旧的文档。 - Peter Chaula
显示剩余15条评论

725
以下是各种对话框的解决方案,包括针对所有API级别(适用于API 8以下,而其他答案则不适用)的AlertDialog.Builder解决方案。还有使用DialogFragment和DialogPreference的AlertDialog解决方案。
以下是代码示例,展示如何覆盖默认的公共按钮处理程序并防止这些不同形式的对话框关闭。所有示例都展示如何防止正面按钮关闭对话框。
注意:关于基本Android类的对话框关闭工作原理以及为什么选择以下方法的描述将在示例后面提供,供那些想要了解更多细节的人参考。
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()

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

方法的解释:

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

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

因此,在使用对话框的设计方式的同时控制其何时关闭,一种方法是先调用dialog.Show(),然后使用dialog.getButton()获取按钮的引用来覆盖点击处理程序。另一种方法是使用setOnShowListener()并实现在OnShowListener中查找按钮视图并替换处理程序。两者之间的功能差别 '几乎' 无法感知,这取决于最初创建对话框实例的线程。通过查看源代码,onShowListener是由一个消息发布到在创建该对话框的线程上运行的处理程序而被调用的。因此,由于您的OnShowListener是由消息队列上发布的消息调用的,所以调用您的监听器可能会在show完成后一段时间内延迟。

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


15
这绝对是最容易实现的方法,并且运行完美。我已经使用了 AlertDialog.Builder - 在show()之后立即更改默认按钮处理程序 ,而且它的效果非常好。 - Reinherd
1
@sogger,老兄,我大胆地编辑了你的精彩答案,因为在第一部分中你写成了dismiss();而不是我认为的dialog.dismiss();非常感谢你提供如此棒的答案! - Fattie
为什么要使用布尔包装对象而不是普通的布尔值? - Roel
3
哇塞,我对安卓的了解越多,就越感到厌恶……只是为了让一个简单的对话框正常工作而已,却需要做这么多事情。花费数小时才能弄清楚如何显示一个对话框。 - SpaceMonkey
1
@harsh_v 更新了答案,为下一个人使用了onResume(),感谢! - Sogger
显示剩余16条评论

65

另一种解决方案

我想从用户体验(UX)角度提出一个替代方案。

为什么要防止对话框在单击按钮时关闭?可能是因为您有一个自定义对话框,用户还没有做出选择或者还没有完全填写完所有内容。如果他们尚未完成,则根本不应允许他们点击确认按钮。只需禁用它,直到一切准备就绪。

其他答案在此处提供了许多覆盖正面按钮单击的技巧。如果这很重要,Android会提供便捷的方法吗?他们没有。

相反,对话框设计指南展示了这样的一个例子。当用户没有做出选择时,确认按钮是禁用的。根本不需要任何覆盖技巧。用户很清楚,在继续之前还需要完成某些操作。

输入图像描述

如何禁用确认按钮

请参见Android文档以创建自定义对话框布局。它建议您将您的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");

注意事项

  • 为简洁起见,我省略了将用户选择信息传递回活动的通信接口。但文档中有展示如何实现。
  • onCreateDialog中,按钮仍然是null,所以我在onResume中禁用了它。这会产生一个不良影响,即如果用户切换到另一个应用程序,然后再回来而没有关闭对话框,则会再次禁用它。可以通过取消任何用户选择或从onCreateDialog调用Runnable以在下一次运行循环中禁用按钮来解决此问题。

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

相关


1
这对于非常简单的对话框来说是可以的,但如果输入验证比你展示的更复杂,或者它包含多个字段,你需要一种告诉用户为什么他们无法继续的方法。 - mhsmith
@mhsmith,确实如此,但对于具有多个字段的复杂内容,我可能不会使用弹出式对话框。 - Suragch

37
我写了一个简单的类(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;
    }   
}

编辑 这里有一个小例子,展示如何使用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

不错。但对我没用。对话框仍然被关闭了。 - Leandros
嗯,那听起来很奇怪。我在我的应用程序中使用这个功能,只有当我显式调用dialog.dismiss()时,按钮才会关闭对话框。你正在测试哪个版本的Android?你能展示一下你使用CustomAlertDialogBuilder的代码吗? - YuviDroid
我认为这是由于以下原因引起的:(在 onClickListener 之后调用 dialog.show())http://pastebin.com/uLnSu5v7 如果我点击 positiveButton,如果 boolean 为 true,则它们会被解除。 - Leandros
我没有使用Activity.onCreateDialog()进行测试。可能它不能以那种方式工作。我将编辑“答案”以包含我如何使用它的小例子。 - YuviDroid
4
对于我来说,这个最新的编辑方式适用!但是,请注意:还有一个要点。Builder.getContext() 只能在 API 11及以上版本中使用。添加一个字段 Context mContext 并在构造函数中设置它。 - Oleg Vaskevich

31

如果你正在使用DialogFragment,那么以下内容可能会对你有所帮助——无论如何,这是处理对话框的推荐方式。

AlertDialogsetButton()方法(我想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按钮的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!这应该会导致你的自定义操作方法只被调用一次,并且默认情况下不会关闭对话框。

24

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

  • 在对话框创建时将 onClickListener 设置为 null
  • 然后在对话框显示后设置 onClickListener

您可以像Tom一样覆盖 onShowListener。 或者,您可以:

  1. 在调用 AlertDialog 的 show() 后获取按钮
  2. 按以下方式设置按钮的 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);
    }
});

14

超级简单的 Kotlin 方法

 with(AlertDialog.Builder(this)) {
        setTitle("Title")
        setView(R.layout.dialog_name)
        setPositiveButton("Ok", null)
        setNegativeButton("Cancel") { _, _ -> }
        create().apply {
            setOnShowListener {
                getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
                    //Validate and dismiss
                    dismiss()
                }
            }
        }
    }.show()

8

对于 API 8 之前的版本,我通过使用布尔标志、忽略监听器以及在文本编辑框内容不正确的情况下再次调用 dialog.show 来解决了这个问题。代码如下:

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;

奇怪的 onDismiss 没有被调用,我的 API 级别是 21。 - duckduckgo

7
这个链接中的答案是一个简单的解决方案,它向后兼容到API 3。它非常类似于Tom Bollwitt的解决方案,但没有使用不太兼容的OnShowListener。

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

  1. 使用DialogBuilder创建对话框
  2. show()显示对话框
  3. 找到显示的对话框中的按钮,并重写它们的onClick事件监听器

由于我正在扩展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)));
}

如此有趣!

4

防止对话框关闭时,点击后只有在联网可用时才能关闭

我也正在尝试做同样的事情,因为我不希望对话框在没有联网的情况下被关闭。

这是我的代码:

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

这很聪明,但我收到了这个错误信息:指定的子项已经有一个父项。您必须先在子项的父项上调用removeView() - Dan Chaltiel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接