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

我有一个EditText输入的对话框。当我点击对话框上的“是”按钮时,它会验证输入,然后关闭对话框。但是,如果输入错误,我想保持在同一个对话框中。每次无论输入是什么,当我点击“否”按钮时,对话框都应该自动关闭。我怎么能禁用这个?顺便说一句,我用了正按钮和负按钮作为对话框上的按钮。

338076 次浏览

编辑:正如一些评论所指出的,这仅适用于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() {
@Overridepublic void onShow(DialogInterface dialogInterface) {
Button button = ((AlertDialog) dialog).getButton(AlertDialog.BUTTON_POSITIVE);button.setOnClickListener(new View.OnClickListener() {
@Overridepublic void onClick(View view) {// TODO Do something
//Dismiss once everything is OK.dialog.dismiss();}});}});dialog.show();

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

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

因此,您可以使用此CustomAlertDialogBuilder而不是使用AlertDialogBuilder。最重要的部分是您不应该调用创建,而应该调用show()方法。我添加了设置取消触摸外部()设置监听器等方法,以便您仍然可以直接在构建器上设置它们。

我在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;}
@Overridepublic CustomAlertDialogBuilder setNegativeButton(CharSequence text, DialogInterface.OnClickListener listener) {mNegativeButtonListener = listener;mNegativeButtonText = text;return this;}
@Overridepublic CustomAlertDialogBuilder setNeutralButton(CharSequence text, DialogInterface.OnClickListener listener) {mNeutralButtonListener = listener;mNeutralButtonText = text;return this;}
@Overridepublic CustomAlertDialogBuilder setPositiveButton(CharSequence text, DialogInterface.OnClickListener listener) {mPositiveButtonListener = listener;mPositiveButtonText = text;return this;}
@Overridepublic CustomAlertDialogBuilder setNegativeButton(int textId, DialogInterface.OnClickListener listener) {setNegativeButton(getContext().getString(textId), listener);return this;}
@Overridepublic CustomAlertDialogBuilder setNeutralButton(int textId, DialogInterface.OnClickListener listener) {setNeutralButton(getContext().getString(textId), listener);return this;}
@Overridepublic CustomAlertDialogBuilder setPositiveButton(int textId, DialogInterface.OnClickListener listener) {setPositiveButton(getContext().getString(textId), listener);return this;}
public CustomAlertDialogBuilder setCanceledOnTouchOutside (boolean cancelOnTouchOutside) {mCancelOnTouchOutside = cancelOnTouchOutside;return this;}


@Overridepublic AlertDialog create() {throw new UnsupportedOperationException("CustomAlertDialogBuilder.create(): use show() instead..");}
@Overridepublic AlertDialog show() {final AlertDialog alertDialog = super.create();
DialogInterface.OnClickListener emptyOnClickListener = new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) { }};

// Enable buttons (needed for Android 1.6) - otherwise later getButton() returns nullif (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 availableif (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 clickedif (mPositiveButtonListener != null) {alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new OnClickListener() {
@Overridepublic void onClick(View v) {mPositiveButtonListener.onClick(alertDialog, AlertDialog.BUTTON_POSITIVE);}});}
if (mNegativeButtonListener != null) {alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE).setOnClickListener(new OnClickListener() {
@Overridepublic void onClick(View v) {mNegativeButtonListener.onClick(alertDialog, AlertDialog.BUTTON_NEGATIVE);}});}
if (mNeutralButtonListener != null) {alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener(new OnClickListener() {
@Overridepublic void onClick(View v) {mNeutralButtonListener.onClick(alertDialog, AlertDialog.BUTTON_NEUTRAL);}});}
return alertDialog;}}

编辑这是一个关于如何使用CustomAlertDialogBuilder的小示例:

// Create the CustomAlertDialogBuilderCustomAlertDialogBuilder dialogBuilder = new CustomAlertDialogBuilder(context);
// Set the usual data, as you would do with AlertDialog.BuilderdialogBuilder.setIcon(R.drawable.icon);dialogBuilder.setTitle("Dialog title");dialogBuilder.setMessage("Some text..");
// Set your buttons OnClickListenersdialogBuilder.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 outsidedialogBuilder.setCanceledOnTouchOutside(false);
// Show the dialogdialogBuilder.show();

干杯,

Yuvi

对于API 8之前的版本,我使用布尔标志、解雇侦听器解决了问题,如果editText的内容不正确,则再次调用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 falseadd_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() {
@Overridepublic void onDismiss(DialogInterface dialog) {//If the error flag was set to true then show the dialog againif (add_client_error == true) {alertClient.show();} else {return;}
}});return true;

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

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

第一个是对话框界面。OnClick监听器,它是setButton()setPositiveButton()setNegativeButton()的参数。

另一个是点击监听器,它将被设置为在按下任何按钮时自动关闭AlertDialog-并且由AlertDialog本身设置。

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

@Overridepublic 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(否则将关闭对话框):

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

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

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

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

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

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

我做了一些小的调整,卡门的代码,因为我是扩展一个编辑文本首选项。

@Overrideprotected void showDialog(Bundle state) {super.showDialog(state);
class mocl implements OnClickListener{private final AlertDialog dialog;public mocl(AlertDialog dialog) {this.dialog = dialog;}@Overridepublic 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)));}

真好玩!

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

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

注意:对于基础android类,对话框关闭如何在引擎盖下工作以及为什么选择以下方法的描述在示例之后,对于那些想要更多详细信息的人来说


AlertDialog. Builder-在show()之后立即更改默认按钮处理程序

AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());builder.setMessage("Test for preventing dialog close");builder.setPositiveButton("Test",new DialogInterface.OnClickListener(){@Overridepublic 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 belowdialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener(){@Overridepublic 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.}});      

对话片段-覆盖onResume()

@Overridepublic Dialog onCreateDialog(Bundle savedInstanceState){AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());builder.setMessage("Test for preventing dialog close");builder.setPositiveButton("Test",new DialogInterface.OnClickListener(){@Overridepublic 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.@Overridepublic 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(){@Overridepublic 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.}});}}

对话框首选项-覆盖showDialog()

@Overrideprotected void onPrepareDialogBuilder(Builder builder){super.onPrepareDialogBuilder(builder);builder.setPositiveButton("Test", this);   //Set the button here so it gets created}
@Overrideprotected 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(){@Overridepublic 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()中传递的任何处理程序,然后调用关闭对话框。

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

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

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

这段代码将为您工作,因为我有一个类似的问题,这对我很有效。:)

1-覆盖你的frament-dialog类中的Onstart()方法。

@Overridepublic 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() {@Overridepublic void onClick(View arg0) {if (edittext.equals("")) {Toast.makeText(getActivity(), "EditText empty",Toast.LENGTH_SHORT).show();} else {D.dismiss(); //dissmiss dialog}}});}}

对于进度对话框

为了防止对话框被自动关闭,您必须在显示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() {
@Overridepublic void onClick ( View v ) {
// Dialog will not get dismissed until you call dismiss() explicitly.
}
});

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

  • 将创建对话框时的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 onClickListenerButton b = dialog.getButton(AlertDialog.BUTTON_POSITIVE);b.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {Log.i(TAG, "ok button is clicked");handleClick(dialog);}});
public class ComentarDialog extends DialogFragment{private EditText comentario;
@Overridepublic 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();}
@Overridepublic void onStart() {super.onStart();
//Obtenemos el AlertDialogAlertDialog dialog = (AlertDialog)getDialog();
dialog.setCanceledOnTouchOutside(false);dialog.setCancelable(false);//Al presionar atras no desaparece
//Implementamos el listener del boton OK para mostrar el toastdialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if(TextUtils.isEmpty(comentario.getText())){Toast.makeText(getActivity(), "Ingrese un comentario", Toast.LENGTH_SHORT).show();return;}else{((AlertDialog)getDialog()).dismiss();}}});
//PersonalizamosResources res = getResources();
//ButtonsButton 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");
//Titleint titleId = res.getIdentifier("alertTitle", "id", "android");View title = dialog.findViewById(titleId);if (title != null) {((TextView) title).setTextColor(color);}
//Title dividerint titleDividerId = res.getIdentifier("titleDivider", "id", "android");View titleDivider = dialog.findViewById(titleDividerId);if (titleDivider != null) {titleDivider.setBackgroundColor(res.getColor(R.color.list_menu_divider));}}}

如果您使用的是material design,我建议您查看素材对话框。它为我修复了与当前打开的Android错误相关的几个问题(参见78088),但最重要的是这张票它有一个autoDismiss标志,可以在使用Builder时设置。

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

警报对话框自定义视图两个按钮(正面和负面)。

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() {@Overridepublic 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));

自定义列表 of正面按钮 of通知戴洛格

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

成交

这可能是很晚的回复,但使用set取消将做的伎俩。

alertDial.setCancelable(false);

您可以在返回之前添加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(){@Overridepublic 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(){@Overridepublic 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 conditionreturn;}
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();
}

另一种解决方案

我想从用户体验的角度给出另一个答案。

为什么要在单击按钮时阻止对话框关闭?大概是因为您有一个自定义对话框,其中用户尚未做出选择或尚未完全填写所有内容。如果他们没有完成,那么您根本不应该允许他们单击正按钮。只需禁用它,直到一切准备就绪。

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

相反,对话设计指南显示了这种情况的一个例子。OK按钮被禁用,直到用户做出选择。根本不需要覆盖技巧。对用户来说,很明显,在继续之前还需要做一些事情。

在此处输入图片描述

如何禁用正按钮

请参阅用于创建自定义对话框布局的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 {
@Overridepublic Dialog onCreateDialog(Bundle savedInstanceState) {
// inflate the custom dialog layoutLayoutInflater inflater = getActivity().getLayoutInflater();View view = inflater.inflate(R.layout.my_dialog_layout, null);
// add a listener to the radio buttonsRadioGroup radioGroup = (RadioGroup) view.findViewById(R.id.radio_group);radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {@Overridepublic void onCheckedChanged(RadioGroup radioGroup, int i) {// enable the positive button after a choice has been madeAlertDialog dialog = (AlertDialog) getDialog();dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(true);}});
// build the alert dialogAlertDialog.Builder builder = new AlertDialog.Builder(getActivity());builder.setView(view).setPositiveButton("OK", new DialogInterface.OnClickListener() {@Overridepublic 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();}
@Overridepublic void onResume() {super.onResume();
// disable positive button by defaultAlertDialog 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() {@Overridepublic void run() {AlertDialog dialog = (AlertDialog) getDialog();dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);}});

Related

使用自定义布局作为您的DialogFragment,并在您的内容下添加LinearLayout,该内容可以设置为无边框以匹配Google材料设计。然后找到新创建的按钮并覆盖它们的OnClickListener

示例:

public class AddTopicFragment extends DialogFragment {
@Overridepublic Dialog onCreateDialog(Bundle savedInstanceState) {final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());// Get the layout inflaterLayoutInflater 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() {@Overridepublic void onClick(View v) {// validate inputsif(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 databaseTopic 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() {@Overridepublic 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 layoutbuilder.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.TextInputLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"app:errorEnabled="true">
<android.support.v7.widget.AppCompatEditTextandroid: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.TextInputLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"app:errorEnabled="true">
<android.support.v7.widget.AppCompatEditTextandroid: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>
<LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><Buttonandroid: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" />
<Buttonandroid: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>

这是最终结果。

防止对话框在单击时关闭,并且仅应在Internet可用时关闭

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

这是我的代码:

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() {@Overridepublic void onClick(DialogInterface dialogInterface, int i) {if(!ifConnected()){builder.show();}}}).setNegativeButton("Cancel", new DialogInterface.OnClickListener() {@Overridepublic 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();}

静态编程语言

val dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_userinput, null)val dialogBuilder = MaterialAlertDialogBuilder(requireContext(), R.style.AlertDialogTheme)   
dialogBuilder.setView(dialogView)dialogBuilder.setCancelable(false)dialogBuilder.setPositiveButton("send",null)dialogBuilder.setNegativeButton("cancel") { dialog,_ ->dialog.dismiss()}

val alertDialog = dialogBuilder.create()alertDialog.show()
val positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE)positiveButton.setOnClickListener {val myInputText = dialogView.etxt_userinput.text.toString().trim()if(myInputText.isNotEmpty()){//Do something}else{//Prompt errordialogView.etxt_userinput.error = "Please fill this"}}

我们只需用dialogBuilder创建一个AlertDialog,然后根据需要设置正按钮

超简单静态编程语言

 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 dismissdismiss()}}}}.show()

我找到了另一种方法来实现这一点…

第1步:将对话框打开代码放在方法(或C中的函数)中。
第2步:在yes(您的正面按钮)的onClick中,调用此对话框打开如果您的条件不满足(如果……否则……),则递归方法。如下所示:

private void openSave() {   
final AlertDialog.Builder builder=new AlertDialog.Builder(Phase2Activity.this);
builder.setTitle("SAVE").setIcon(R.drawable.ic_save_icon).setPositiveButton("Save", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterface, int i) {                    
if((!editText.getText().toString().isEmpty() && !editText1.getText().toString().isEmpty())){
createPdf(fileName,title,file);                            
}else {openSave();Toast.makeText(Phase2Activity.this, "Some fields are empty.", Toast.LENGTH_SHORT).show();}
                    
}).setNegativeButton("Cancel", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterface, int i) {dialogInterface.dismiss();}}).setCancelable(false).create().show();
}

但这会使对话框消失一会儿,它会立即再次出现。:)

使用此代码,您可以在单击正按钮时阻止对话框关闭。您也可以使用否定按钮实现相同的功能。

    final AlertDialog alertDialog = alertDialogBuilder.setCancelable(false).setTitle("TITLE");.setPositiveButton("OK", null).setNegativeButton("CANCEL",(dialog, id) -> {dialog.cancel();}).show();Button positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);positiveButton.setOnClickListener(v -> {// check whatever you wantif(checkMyCondition())dialog.cancel();})