Zurück-Schaltfläche erkennen, Dialogfragment jedoch nicht schließen

76

Ich habe ein Dialogfragment für ein schwebendes Dialogfeld, das eine spezielle Tastatur enthält, die angezeigt wird, wenn ein Benutzer in ein EditText-Feld drückt (die Anzeige des normalen IME wird gestoppt).

Ich möchte, dass die Tastatur geschlossen wird (Sichtbarkeit = GEGANGEN), wenn der Benutzer die Zurück-Taste drückt (genau wie bei einem normalen IME-Dienst), der Dialog jedoch sichtbar bleibt. Es scheint jedoch keine Möglichkeit zu geben, dies zu tun, soweit ich aus meiner ziemlich ausführlichen Lektüre über SO und anderswo ersehen kann.

Wenn ich den Dialog als nicht stornierbar einstelle, werde ich nicht von onCancel () oder onDismiss () benachrichtigt, da der Dialog nicht stornierbar ist.

Wenn ich den Dialog auf abbrechbar setze, werde ich benachrichtigt, aber der Dialog wird geschlossen.

Ich kann dem Dialogfeld im Fragment keinen onKeyListener hinzufügen, da er vom System ersetzt wird, damit das Fragment den Lebenszyklus des Dialogfelds verarbeiten kann.

Gibt es eine Möglichkeit, dies zu tun? Oder wurde der Zugriff auf die Erkennung von Schlüsselereignissen für die Zwecke des Fragment-Systems vollständig gesperrt?

user3227652
quelle

Antworten:

175

Der beste und sauberste Weg ist, onBackPressed () in dem Dialogfeld zu überschreiben, das Sie in onCreateDialog () erstellt haben.

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    return new Dialog(getActivity(), getTheme()){
        @Override
        public void onBackPressed() {
            //do your stuff
        }
    };
}
Ian Wong
quelle
9
Die einzige Lösung, die ich gefunden habe, funktioniert tatsächlich richtig.
Yoann Hercouet
6
Dies funktioniert jedoch nicht in DialogFragments, da die DialogFragment-Klasse kein onBackPressed () enthält.
Glen Pierce
10
DialogFragments umschließen einen Dialog - onCreateDialog erstellt diesen Dialog. Es funktioniert in DialogFragments.
Tom
Ich kann dies nur als beste und einfachste Lösung bestätigen. Vielen Dank für das Teilen dieser @Ian Wong
Menion Asamm
1
Auf jeden Fall sollte eine akzeptierte Antwort sein. Die mit Abstand nativste Lösung!
egorikem
72

Ich hatte das gleiche Problem wie Sie und habe es behoben, indem ich den onKeyListener an das Dialogfragment angehängt habe.

onResume()Fügen Sie in die Methode der Klasse, die DialogFragment erweitert, diesen Code ein:

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

Hier ist eines der Probleme, die Sie finden können, dass dieser Code zweimal ausgeführt wird: eines, wenn der Benutzer die Zurück-Taste drückt, und eines, wenn er geht, um ihn zu drücken. In diesem Fall müssen Sie nach Ereignis filtern:

@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
        }
    });
}
Juan Pedro Martinez
quelle
Anstatt den Filter zu verwenden, habe ich getDialog (). SetOnKeyListener (null) hinzugefügt, wodurch der zweite Aufruf verhindert wird.
Lucas Arrefelt
24

Als Ergänzung zu Juan Pedro Martinez 'Antwort hielt ich es für hilfreich, eine bestimmte Frage (eine, die ich hatte) zu klären, wenn ich mir diesen Thread anschaue.

Wenn Sie ein neues DialogFragment erstellen möchten und es so haben, dass der Benutzer es nur mit der Zurück-Schaltfläche abbrechen kann, wodurch zufällige Bildschirmberührungen daran gehindert werden, das Fragment vorzeitig abzubrechen, ist dies der Code, den Sie verwenden würden.

In welchem ​​Code auch immer Sie das DialogFragment aufrufen, müssen Sie die Einstellung zum Abbrechen auf false setzen, damit das Fragment durch NICHTS verworfen wird, keine streunenden Bildschirmberührungen auftreten usw.

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

Anschließend fügen Sie in Ihrem DialogFragment, in diesem Fall MyDaialogFragment.java, den Überschreibungscode onResume hinzu, damit der Dialog auf die Schaltfläche Zurück wartet. Wenn es gedrückt wird, wird entlassen () ausgeführt, um das Fragment zu schließen.

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

Jetzt wird Ihr Dialogfeld mit "setCancelable" auf false aufgerufen, was bedeutet, dass nichts (keine externen Klicks) es abbrechen und herunterfahren kann und (innerhalb des Dialogfelds selbst) nur die Schaltfläche "Zurück" zum Schließen zulässt.

Ganbatte!

Brandon
quelle
1
Perfekt, danke, ich wollte versehentliche Klicks von außen verhindern und gleichzeitig die Funktionalität der Zurück-Schaltfläche beibehalten. Für mich war alles, was ich tun musste, setCancelable (false) für die Dialoginstanz in onCreateView im DialogFragment.
Meanman
1
Danke, diese Antwort passt am besten zu meinem Zustand.
Araju
16

Wie hat das niemand vorgeschlagen?

public Dialog onCreateDialog(Bundle savedInstanceState) {
  Dialog dialog = super.onCreateDialog(savedInstanceState);

  // Add back button listener
  dialog.setOnKeyListener(new Dialog.OnKeyListener() {
    @Override
    public boolean onKey(DialogInterface dialogInterface, int keyCode, KeyEvent keyEvent) {
      // getAction to make sure this doesn't double fire
      if (keyCode == KeyEvent.KEYCODE_BACK && keyEvent.getAction() == KeyEvent.ACTION_UP) {
        // Your code here
        return true; // Capture onKey
      }
      return false; // Don't capture
    }
  });

  return dialog;
}
Andrew James
quelle
13

Verwenden Sie die Überschreibungsmethode Fragment onCancel. Es wird aufgerufen, wenn Sie zurück drücken. Hier ist ein Beispiel:

@Override
public void onCancel(DialogInterface dialog) {
    super.onCancel(dialog);

    // Add you codition
}
Manimaran A.
quelle
2
Beachten Sie, dass Sie mit diesem Ansatz nicht festlegen können, ob das DialogFragment geschlossen wird oder nicht. Sie können nur benachrichtigt werden, dass es entlassen werden soll
Leo Droidcoder
In der Tat @Leo Droidcoder Irgendeine Idee, wie man die vor dem Dialogfragment gedrückte Zurück-Taste abfängt, kann nicht verworfen werden?
18.
3

Überschreiben Sie beim Erstellen des Dialogfelds sowohl onBackPressed als auch 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
                    ...
            }
        };
Android-Entwickler
quelle
0

Verwenden Sie den onDismiss () - Rückruf von DialogFragment mit einem closeActivity- Flag

private var closeActivity: Boolean = true    

override fun onDismiss(dialog: DialogInterface?) {
        super.onDismiss(dialog)

        if (closeActivity) {
            activity!!.finish()
        }
    }
Vasudev
quelle
0

Verhindern, dass DialogFragment abgebrochen wird:

dialog.setCanceledOnTouchOutside(false)
dialog.setCancelable(false)
dialog.setOnKeyListener { dialog, keyCode, event ->
    keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_UP
}
Benny
quelle