Detectar el botón Atrás pero no descartar el diálogo

Tengo un diálogo para un cuadro de diálogo flotante que incluye un teclado especial que aparece cuando un usuario presiona dentro de un campo EditText (el IME normal no se muestra).

Quisiera que el teclado fuera rechazado (visibilidad = GONE) cuando el usuario presiona el botón de la parte posterior (apenas como con un servicio normal de IME) pero el diálogo permanece visible. Sin embargo, no parece haber una manera de hacer esto en la medida de lo que puedo ver de mi lectura bastante amplia sobre SO y en otros lugares.

Si configuro el cuadro de diálogo para que no sea cancelable, entonces no se me notifica por onCancel () o onDismiss () porque el cuadro de diálogo no se puede cancelar.

Si establezco el diálogo para ser cancelable entonces me notifican, pero el diálogo se despide.

No puedo adjuntar un onKeyListener al diálogo en el fragmento porque es reemplazado por el sistema para que el fragmento pueda manejar el ciclo de vida del diálogo.

¿Hay alguna manera de hacer esto? ¿O el acceso a la detección de eventos claves ha sido completamente cercado para los propósitos del sistema Fragment?

La mejor manera y manera más limpia es anular onBackPressed () en el diálogo que creó en onCreateDialog ().

@Override public Dialog onCreateDialog(Bundle savedInstanceState) { return new Dialog(getActivity(), getTheme()){ @Override public void onBackPressed() { //do your stuff } }; } 

Tuve el mismo problema que tú y lo he arreglado adjuntando el onKeyListener a la dialogfragment.

En el método onResume() de la clase que se extienden de DialogFragment poner estos pedazo de código:

  getDialog().setOnKeyListener(new OnKeyListener() { @Override public boolean onKey(android.content.DialogInterface dialog, int keyCode,android.view.KeyEvent event) { if ((keyCode == android.view.KeyEvent.KEYCODE_BACK)) { //Hide your keyboard here!!! return true; // pretend we've processed it } else return false; // pass on to be processed as normal } }); 

Aquí uno de los problemas que puedes encontrar es que este código va a ser ejecutado dos veces: uno cuando el usuario pulsa el botón de atrás y otro cuando salga para presionarlo. En ese caso, tiene que filtrar por evento:

 @Override public void onResume() { super.onResume(); getDialog().setOnKeyListener(new OnKeyListener() { @Override public boolean onKey(android.content.DialogInterface dialog, int keyCode, android.view.KeyEvent event) { if ((keyCode == android.view.KeyEvent.KEYCODE_BACK)) { //This is the filter if (event.getAction()!=KeyEvent.ACTION_DOWN) return true; else { //Hide your keyboard here!!!!!! return true; // pretend we've processed it } } else return false; // pass on to be processed as normal } }); } 

Como adición a la respuesta de Juan Pedro Martínez, pensé que sería útil aclarar una pregunta específica (una que tenía) al mirar este hilo.

Si desea crear un nuevo DialogFragment y tenerlo para que el usuario solo pueda cancelarlo con el botón de retroceso, lo que elimina los toques de pantalla aleatorios al cancelar el fragmento prematuramente, entonces este es el código que usaría.

En cualquier código que usted llama el DialogFragment usted necesita fijar el ajuste cancelable a falso de modo que NADA desecha el fragmento, no toca la pantalla perdida, el etc.

 DialogFragment mDialog= new MyDialogFragment(); mDialog.setCancelable(false); mDialog.show(getFragmentManager(), "dialog"); 

A continuación, dentro de DialogFragment, en este caso MyDaialogFragment.java, agrega el código de anulación onResume para que el diálogo escuche el botón Atrás. Cuando se presiona, ejecutará la operación dismiss () para cerrar el fragmento.

 @Override public void onResume() { super.onResume(); getDialog().setOnKeyListener(new OnKeyListener() { @Override public boolean onKey(android.content.DialogInterface dialog, int keyCode,android.view.KeyEvent event) { if ((keyCode == android.view.KeyEvent.KEYCODE_BACK)) { // To dismiss the fragment when the back-button is pressed. dismiss(); return true; } // Otherwise, do nothing else else return false; } }); 

Ahora su diálogo será llamado con el "setCancelable" a false, lo que significa que nada (sin clics fuera) puede cancelarlo y cerrarlo, y permitiendo (desde el propio diálogo) sólo el botón de volver a cerrarlo.

Ganbatte!

 @Override public Dialog onCreateDialog(Bundle savedInstanceState) { Dialog dialog = new Dialog(getActivity(), getTheme()) { @Override public void onBackPressed() { //your code } }; return dialog; } 

Al crear el cuadro de diálogo, anule ambos onBackPressed y onTouchEvent:

  final Dialog dialog = new Dialog(activity) { @Override public boolean onTouchEvent(final MotionEvent event) { //note: all touch events that occur here are outside the dialog, yet their type is just touching-down boolean shouldAvoidDismissing = ... ; if (shouldAvoidDismissing) return true; return super.onTouchEvent(event); } @Override public void onBackPressed() { boolean shouldAvoidDismissing = ... ; if (!shouldSwitchToInviteMode) dismiss(); else ... } }; 
  • Tema de DatePickerDialog de Android 6.0
  • Superpuesto por la barra de estado cuando se muestra el fragmento de diálogo, solo en Android4.4
  • Cambiar DialogFragment entrar / salir de la transición justo antes de despedir
  • Devolución de datos de un DialogFragment a un adaptador
  • Ocultar el teclado al mostrar DialogFragment en la tableta?
  • DialogFragment de getView devuelve null en onDismiss
  • Pantalla completa DialogFragment se superpone con StatusBar
  • Android: NullPointerException en DialogFragment.dismissInternal en DialogFragment.dismissAllow
  • Acción ActionBar en DialogFragment
  • ¿Cómo descartar de forma segura DialogFragment en onstop ()?
  • BottomSheetDialogFragment - escucha despedido por evento de usuario
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.