Impedir que el botón Atrás cierre un cuadro de diálogo

6 minutos de lectura

avatar de usuario
capitánprog

Estoy tratando de evitar que se cierre un cuadro de AlertDialog al presionar el botón Atrás en Android. Seguí los dos métodos populares en este hilo, y con System.out.println puedo ver que en ambos casos el código se ejecuta. Sin embargo, el botón Atrás todavía cierra el cuadro de diálogo.

¿Qué podría estar haciendo mal? En última instancia, estoy tratando de evitar que el botón Atrás cierre un cuadro de diálogo: es un descargo de responsabilidad que se muestra la primera vez que se ejecuta la aplicación y no quiero que el usuario tenga otra opción que presionar el botón “Aceptar” en para que la aplicación continúe.

  • Si requiere que un usuario acepte una licencia o un descargo de responsabilidad (o lo que sea), entonces DEBER permitir que se nieguen. Si hacen clic en el BACK y luego asegúrese de que el cuadro de diálogo de licencia/descargo de responsabilidad vuelva a aparecer la próxima vez que inicien la aplicación y una y otra vez hasta que acepten o eliminen la aplicación de su dispositivo. Si elige utilizar el enfoque sugerido por Sam, entonces DEBER proporcionar un botón ‘Rechazar’ pero luego volver a crear la licencia/descargo de responsabilidad la próxima vez que inicien la aplicación.

    – Squonk

    27 de agosto de 2012 a las 23:08

  • Quitaría una app que me da “aceptar” como única opción… ¡y ni se te ocurra deshabilitar el botón home!

    – WarrenFaith

    27 de agosto de 2012 a las 23:49

  • La aplicación se puede cerrar presionando el botón de inicio, pero esencialmente la aplicación no puede avanzar más allá del descargo de responsabilidad si no se acepta la licencia. @Squonk, mencionas que yo deber permitir que se nieguen; ¿Es esto un problema legal? es decir, ¿existe una ley que establezca que el software debe ser utilizable (si se ha pagado) sin aceptar el contrato de licencia? Nota: ya tengo un botón “rechazar”, y al presionarlo aparece un Toast() que dice que debe aceptar el acuerdo para usar la aplicación. Por lo tanto, el cuadro de diálogo persiste hasta que se presiona aceptar.

    – CapitánProg

    28 de agosto de 2012 a las 14:37


  • @CaptainProg: No soy abogado, pero sospecho que en algunos países podría considerarse un legal tema. No estoy sugiriendo que permita que las personas usen su aplicación si rechazan/rechazan el descargo de responsabilidad. Todo lo que digo es que es una mala política, malas relaciones con los clientes (incluso si la aplicación es gratuita) y malo para el UX bloquear a alguien. Simplemente haga que la opción ‘rechazar’ cierre la aplicación y la próxima vez que el usuario intente iniciar él, presenta el mismo diálogo. No se limite a abrir un Toastdéjelos encerrados y confíe en ellos usando thw HOME botón para salir.

    – Squonk

    28 de agosto de 2012 a las 20:47


avatar de usuario
Sam

Simplemente use el setCancelable() rasgo:

AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setCancelable(false);

Esto evita que el botón Atrás cierre el cuadro de diálogo, pero deja intacto el botón “negativo” si elige usarlo.


Si bien cualquier usuario que no quiera aceptar sus términos de servicio puede presionar el botón de inicio, a la luz del comentario de Squonk, aquí hay dos formas más de evitar que “retroceda” del acuerdo de usuario. Uno es un simple botón “Rechazar” y el otro anula el botón Atrás en el cuadro de diálogo:

builder.setNegativeButton("Refuse", new OnClickListener() {
           @Override
           public void onClick(DialogInterface dialog, int which) {
               finish();
           }
       })
       .setOnKeyListener(new OnKeyListener() {
           @Override
           public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
               if(keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP)
                   finish();
               return false;
           }
       });

  • Además, si usa un DialogFragmentdeberías llamar setCancelable en eso y no en el Dialog sí mismo

    – Kuffs

    21 de agosto de 2015 a las 8:05


  • Muchas gracias @Kuffs. ¡Lo estaba configurando en el diálogo y me preguntaba por qué no funciona!

    – sasikt

    7 de octubre de 2015 a las 6:04

Para evitar que el botón Atrás cierre un Diálogo (sin depender de la Actividad), basta con el siguiente código:

alertDialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
    @Override
    public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
        // Prevent dialog close on back press button
        return keyCode == KeyEvent.KEYCODE_BACK;
    }
});

  • Funcionó muy bien en mi caso. Tuve que cargar un WebView en mi aplicación tuve que comprobar canGoBack() y cerrar el cuadro de diálogo si era falso.

    – Aloha

    10 jun 2016 a las 14:40

  • funcionado bien. Seguid así

    – Pir Fahim Shah

    19 de noviembre de 2021 a las 8:02

Cuando usas DialogFragment tendrás que llamar setCancelable() en el fragmento, no en el diálogo:

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    dialog = new ProgressDialog(getActivity());
    dialog.setIndeterminate(true);
    dialog.setMessage(...);
    setCancelable(false);

    return dialog;
}

Vocación dialog.setCancelable() parece no tener efecto. Parece que DialogFragment no toma nota de la configuración del cuadro de diálogo para la cancelabilidad.

Usar setCancelable(false)

SampleDialog sampleDialog = SampleDialog.newInstance();
sampleDialog.setCancelable(false);
sampleDialog.show(getSupportFragmentManager(), SampleDialog.class.getSimpleName());

Solo esto funcionó para mí:

AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(title);
builder.setMessage(content);

/**
 * Make it when the Back button is pressed, the dialog isn't dismissed.
 */
builder.setOnKeyListener(new DialogInterface.OnKeyListener() {
    @Override
    public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
        if(keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
            Utilities.makeToast(getContext(), "There is no way back!");
            return true; // Consumed
        }
        else {
            return false; // Not consumed
        }
    }
});

Dialog dialog = builder.create();

/**
 * Make it so touching on the background activity doesn't close the dialog
 */
dialog.setCanceledOnTouchOutside(false);

return dialog;

Como puede ver, también agregué un dialog.setCanceledOnTouchOutside(false); línea, por lo que al tocar fuera del cuadro de diálogo tampoco se cerrará.

avatar de usuario
Ricardo Saracino

En JQuery Mobile, una ventana emergente agrega un hash a la URL, el siguiente código permite que la parte posterior descarte la ventana emergente cuando está abierta y regrese a la aplicación cuando está cerrada. Podría usar la misma lógica para un marco de interfaz de usuario personalizado.

@Override
public void onBackPressed() {

    // check if modal is open #&ui-state=dialog

    if (webView.getVisibility() == View.VISIBLE && webView.getUrl().contains("#&ui-state=dialog")) {
        // don't pass back button action
        if (webView.canGoBack()) {
            webView.goBack();
        }
    } else {
        // pass back button action
        super.onBackPressed();
    }
}

avatar de usuario
Stu Stirling

Agregar setCancelable(false) para evitar que el botón Atrás cierre un cuadro de diálogo.

Por ejemplo :

AlertDialog.Builder builder = AlertDialog.Builder(this)
Dialog dialog = builder.create()
dialog.setCancelable(false)
dialog.setCanceledOnTouchOutside(false)

Esto evitará que el usuario cancele el diálogo cuando presione el botón Atrás o toque fuera de la ventana de diálogo.

¿Ha sido útil esta solución?