Cómo evitar que un cuadro de diálogo se cierre cuando se hace clic en un botón

Tengo un diálogo con EditText para la entrada. Cuando hago clic en el botón "Sí" en el diálogo, validará la entrada y luego cerraré el diálogo. Sin embargo, si la entrada es incorrecta, quiero permanecer en el mismo diálogo. Cada vez que importe cual sea la entrada, el diálogo debe cerrarse automáticamente cuando hago clic en el botón "no". ¿Cómo puedo inhabilitar esto? Por cierto, he utilizado PositiveButton y NegativeButton para el botón de diálogo.

EDIT: Esto sólo funciona en la API 8 +, como se señala en algunos de los comentarios.

Esta es una respuesta tardía, pero puede agregar un onShowListener al AlertDialog donde puede entonces anular el onClickListener del botón.

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

Aquí hay algunas soluciones para todos los tipos de diálogos incluyendo una solución para AlertDialog.Builder que funcionará en todos los niveles de API (funciona debajo de API 8, que la otra respuesta aquí no). Existen soluciones para AlertDialogs que utilizan AlertDialog.Builder, DialogFragment y DialogPreference.

A continuación se muestran los ejemplos de código que muestran cómo anular el controlador de botones común predeterminado y evitar que el diálogo se cierre para estas diferentes formas de diálogos. Todos los ejemplos muestran cómo evitar que el botón positivo cierre el diálogo.

Nota: Una descripción de cómo funciona el cierre de diálogo bajo el capó para las clases básicas de Android y por qué se eligen los siguientes enfoques sigue a los ejemplos, para aquellos que quieran más detalles


AlertDialog.Builder – Cambiar el manejador de botones predeterminado inmediatamente después de 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 – anula 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 – anula 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. } }); } 

Explicación de los enfoques:

Buscando a través de código fuente de Android la implementación predeterminada de AlertDialog funciona mediante el registro de un controlador de botón común a todos los botones reales en OnCreate (). Cuando se hace clic en un botón, el controlador de botones común reenvía el evento de clic a cualquier controlador que haya pasado en setButton () y, a continuación, las llamadas descartan el diálogo.

Si desea evitar que un cuadro de diálogo se cierre cuando se presiona uno de estos botones, debe reemplazar el controlador de botones común por la vista real del botón. Debido a que se asigna en OnCreate (), debe reemplazarlo después de que se llame a la implementación OnCreate () predeterminada. OnCreate se llama en el proceso del método show (). Puede crear una clase de diálogo personalizada y reemplazar OnCreate () para llamar a super.OnCreate () y reemplazar los controladores de botones, pero si crea un diálogo personalizado no obtiene el generador de forma gratuita, en cuyo caso, ¿cuál es el punto ?

Por lo tanto, al utilizar un diálogo de la forma en que está diseñado, pero con el control cuando se descarta, una aproximación es llamar a dialog.Show () primero, y luego obtener una referencia al botón con dialog.getButton () para anular el controlador de clics. Otro enfoque es usar setOnShowListener () e implementar la búsqueda de la vista de botón y reemplazar el manejador en OnShowListener. La diferencia funcional entre los dos es "casi" nill, dependiendo de qué hilo crea originalmente la instancia de diálogo. Mirando a través del código fuente, el onShowListener es llamado por un mensaje enviado a un controlador que se ejecuta en el subproceso que creó ese diálogo. Por lo tanto, ya que su OnShowListener es llamado por un mensaje publicado en la cola de mensajes es técnicamente posible que la llamada a su oyente se retrasa algún tiempo después de finalizada la demostración.

Por lo tanto, creo que el enfoque más seguro es el primero: llamar a show.Dialog (), entonces inmediatamente en la misma ruta de ejecución reemplazar los controladores de botón. Dado que el código que llama show () funcionará en el subproceso principal de GUI, significa que cualquier código que sigas show () con será ejecutado antes de cualquier otro código en ese hilo, mientras que el tiempo del método OnShowListener está a merced de La cola de mensajes.

He escrito una clase simple (un AlertDialogBuilder) que se puede utilizar para desactivar la característica de auto-descarte al presionar los botones del diálogo.

Es compatible también con Android 1.6, por lo que no hace uso de OnShowListener (que está disponible sólo API> = 8).

Por lo tanto, en lugar de utilizar AlertDialog.Builder puede utilizar este CustomAlertDialogBuilder. La parte más importante es que no debe llamar a create () , sino sólo al método show () . He añadido métodos como setCanceledOnTouchOutside () y setOnDismissListener de modo que todavía puede configurar directamente en el constructor.

Lo probé en Android 1.6, 2.x, 3.xy 4.x por lo que debería funcionar bastante bien. Si encuentra algunos problemas, por favor, comente aquí.

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

EDIT Este es un pequeño ejemplo de cómo usar 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(); 

Aclamaciones,

Yuvi

Aquí es algo si está utilizando DialogFragment – que es la forma recomendada para manejar los diálogos de todos modos.

Lo que sucede con el método setButton() de setButton() e imagino lo mismo con AlertDialogBuilder setPositiveButton() y setNegativeButton() ) de setNegativeButton() es que el botón que establezca (por ejemplo, AlertDialog.BUTTON_POSITIVE ) con él realmente disparará dos diferentes objetos OnClickListener cuando se presione.

El primero es DialogInterface.OnClickListener , que es un parámetro para setButton() , setPositiveButton() y setNegativeButton() .

El otro es View.OnClickListener , que se configurará para descartar automáticamente AlertDialog cuando se AlertDialog cualquiera de sus botones y se establezca por AlertDialog .

Lo que puede hacer es utilizar setButton() con null como DialogInterface.OnClickListener , para crear el botón y, a continuación, llamar a su método de acción personalizado dentro de View.OnClickListener . Por ejemplo,

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

A continuación, puede anular los botones View.OnClickListener ' View.OnClickListener ' de View.OnClickListener (que de lo contrario descartaría el diálogo) en el DialogFragment onResume() :

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

Tendrás que configurar esto en el método onResume() porque getButton() devolverá null hasta después de que se muestre el diálogo!

Esto debería hacer que su método de acción personalizado sólo se llame una vez y el diálogo no se eliminará de forma predeterminada.

Inspirado por la respuesta de Tom, creo que la idea aquí es:

  • Establezca onClickListener durante la creación del diálogo a null
  • A continuación, establezca un onClickListener después de onClickListener el cuadro de diálogo.

Puede sobrescribir el onShowListener como Tom. Alternativamente, puede

  1. Obtener el botón después de llamar al show() de AlertDialog show()
  2. Establecer los botones ' onClickListener como sigue (un poco más legible, creo).

Código:

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

Para pre API 8 i resolvió el problema usando una bandera booleana, un oyente de despido y llamada dialog.show de nuevo si en el caso de que el contenido del editText no era correcto. Me gusta esto:

 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; 

La respuesta en este enlace es una solución simple, y que es compatible de nuevo con la API 3. Es muy similar a la solución de Tom Bollwitt, pero sin utilizar el OnShowListener menos compatible.

Sí tu puedes. Usted necesita básicamente:

  1. Crear el diálogo con DialogBuilder
  2. Mostrar () el diálogo
  3. Encuentre los botones en el cuadro de diálogo mostrado y anule su onClickListener

Hice pequeñas adaptaciones al código de Kamen ya que estaba extendiendo una EditTextPreference.

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

¡Qué divertido!

Una solución alternativa

Me gustaría presentar una respuesta alternativa desde una perspectiva UX.

¿Por qué desea impedir que un diálogo se cierre cuando se hace clic en un botón? Presumible es porque usted tiene un diálogo personalizado en el que el usuario no ha hecho una elección o no ha completado completamente todo aún. Y si no están terminados, entonces usted no debe permitir que haga clic en el botón positivo en absoluto. Simplemente deshabilita hasta que todo esté listo.

Las otras respuestas aquí dan muchos trucos para reemplazar el botón positivo. Si eso fuera importante, ¿no habría hecho Android un método conveniente para hacerlo? No lo hicieron.

En su lugar, la guía de diseño Dialogs muestra un ejemplo de tal situación. El botón Aceptar se desactiva hasta que el usuario elija. No es necesario hacer trucos superiores. Es obvio que todavía hay que hacer algo antes de continuar.

Introduzca aquí la descripción de la imagen

Cómo deshabilitar el botón positivo

Consulte la documentación de Android para crear un diseño de diálogo personalizado . Se recomienda que coloque su AlertDialog dentro de un DialogFragment . A continuación, todo lo que necesita hacer es establecer oyentes en los elementos de diseño para saber cuándo habilitar o deshabilitar el botón positivo.

  • Si el diálogo personalizado tiene botones de radio, utilice RadioGroup.OnCheckedChangeListener .
  • Si su cuadro de diálogo personalizado tiene casillas de verificación, utilice CompoundButton.OnCheckedChangeListener .
  • Si su diálogo personalizado tiene un EditText , utilice TextWatcher .

El botón positivo se puede desactivar de la siguiente manera:

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

Aquí está todo un DialogFragment trabajo con un botón positivo deshabilitado tal como se podría utilizar en la imagen de arriba.

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

El diálogo personalizado se puede ejecutar desde una actividad como esta:

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

Notas

  • En aras de la brevedad, he omitido la interfaz de comunicación para pasar la información de elección del usuario de nuevo a la actividad. Sin embargo, la documentación muestra cómo se hace esto.
  • El botón sigue siendo null en onCreateDialog así que lo inhabilité en onResume . Esto tiene el efecto indeseable de deshabilitarlo de nuevo si el usuario cambia a otra aplicación y luego vuelve sin descartar el diálogo. Esto podría solucionarse también seleccionando las opciones de los usuarios o llamando a Runnable de onCreateDialog para desactivar el botón en el siguiente ciclo de ejecución.

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

Este código funcionará para usted, porque tuve un problema simmilar y esto funcionó para mí. 🙂

1- Método Override Onstart () en su clase de diálogo de fragmentos.

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

Esta es probablemente una respuesta muy tarde, pero usar setCancelable hará el truco.

 alertDial.setCancelable(false); 

Para ProgressDialogs

Para evitar que el cuadro de diálogo se OnClickListener automáticamente tiene que configurar OnClickListener después de OnClickListener el ProgressDialog , así:

 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. } }); 
 public class ComentarDialog extends DialogFragment{ private EditText comentario; @Override public Dialog onCreateDialog(Bundle savedInstanceState) { AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); LayoutInflater inflater = LayoutInflater.from(getActivity()); View v = inflater.inflate(R.layout.dialog_comentar, null); comentario = (EditText)v.findViewById(R.id.etxt_comentar_dialog); builder.setTitle("Comentar") .setView(v) .setPositiveButton("OK", null) .setNegativeButton("CANCELAR", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { } }); return builder.create(); } @Override public void onStart() { super.onStart(); //Obtenemos el AlertDialog AlertDialog dialog = (AlertDialog)getDialog(); dialog.setCanceledOnTouchOutside(false); dialog.setCancelable(false);//Al presionar atras no desaparece //Implementamos el listener del boton OK para mostrar el toast dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(TextUtils.isEmpty(comentario.getText())){ Toast.makeText(getActivity(), "Ingrese un comentario", Toast.LENGTH_SHORT).show(); return; } else{ ((AlertDialog)getDialog()).dismiss(); } } }); //Personalizamos Resources res = getResources(); //Buttons Button positive_button = dialog.getButton(DialogInterface.BUTTON_POSITIVE); positive_button.setBackground(res.getDrawable(R.drawable.btn_selector_dialog)); Button negative_button = dialog.getButton(DialogInterface.BUTTON_NEGATIVE); negative_button.setBackground(res.getDrawable(R.drawable.btn_selector_dialog)); int color = Color.parseColor("#304f5a"); //Title int titleId = res.getIdentifier("alertTitle", "id", "android"); View title = dialog.findViewById(titleId); if (title != null) { ((TextView) title).setTextColor(color); } //Title divider int titleDividerId = res.getIdentifier("titleDivider", "id", "android"); View titleDivider = dialog.findViewById(titleDividerId); if (titleDivider != null) { titleDivider.setBackgroundColor(res.getColor(R.color.list_menu_divider)); } } } 

Puede agregar builder.show (); Después del mensaje de validación antes del retorno;

Me gusta esto

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

If you are using material design I would suggest checking out material-dialogs . It fixed several issues for me related to currently open Android bugs (see 78088 ), but most importantly for this ticket it has an autoDismiss flag that can be set when using the Builder .

It could be built with easiest way:

Alert Dialog with Custom View and with two Buttons (Positive & Negative).

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

CustomClickLister of Positive Button of Alert Dailog :

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

Hecho

My solution is simple, just use a custom layout for your DialogFragment and add a LinearLayout under your content which can be styled as borderless to match Google Material Design, then find the newly created Buttons and Override their OnClickListener: DialogFragment.java code:

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

dialog_add_topic.xml

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

This is the final result:

  • Android - MediaController de VideoView dentro de diálogo aparece detrás del diálogo
  • ¿Cómo puedo mostrar mi actividad como un diálogo en Android?
  • Cómo iniciar una actividad desde un diálogo en Android
  • Cómo establecer el contenido de setSingleChoiceItems en onPrepareDialog?
  • Android - Cambiar el fondo del título del diálogo personalizado
  • SendUserActionEvent () mView == null después de hacer clic en el botón
  • Establecer el título del fragmento de diálogo para mostrar desde la derecha
  • Totalmente transparente ActionBarSherlock utilizando el tema
  • Objetos EditText múltiples en AlertDialog
  • Crear cuadro de diálogo con barra de progreso en android
  • Evitar que ProgressDialog sea rechazado cuando hago clic en el botón de búsqueda (Android)
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.