631 Stimmen

Wie implementiert man onBackPressed() in Fragments?

Gibt es eine Möglichkeit, wie wir die onBackPressed() in Android Fragment ähnlich wie in Android Activity implementieren?

Da der Fragment-Lebenszyklus nicht über onBackPressed() . Gibt es eine andere alternative Methode zur Überwindung onBackPressed() in Android 3.0-Fragmenten?

28voto

B-GangsteR Punkte 2294

Verwendung von Komponente Navigation Sie können es schaffen wie diese :

Java

public class MyFragment extends Fragment {

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // This callback will only be called when MyFragment is at least Started.
    OnBackPressedCallback callback = new OnBackPressedCallback(true /* enabled by default */) {
        @Override
        public void handleOnBackPressed() {
            // Handle the back button event
        }
    });
    requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);

    // The callback can be enabled or disabled here or in handleOnBackPressed()
}
...
}

Kotlin

class MyFragment : Fragment() {

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // This callback will only be called when MyFragment is at least Started.
    val callback = requireActivity().onBackPressedDispatcher.addCallback(this) {
        // Handle the back button event
    }

    // The callback can be enabled or disabled here or in the lambda
}
...
}

21voto

mwieczorek Punkte 1948

Da diese Frage und einige der Antworten über fünf Jahre alt sind, möchte ich meine Lösung mitteilen. Dies ist eine Fortsetzung und Modernisierung der Antwort von @oyenigun

UPDATE: Am Ende dieses Artikels habe ich eine alternative Implementierung hinzugefügt, die eine abstrakte Fragment-Erweiterung verwendet, die die Aktivität überhaupt nicht mit einbezieht, was für jeden nützlich wäre, der eine komplexere Fragment-Hierarchie mit verschachtelten Fragmenten hat, die ein unterschiedliches Rückverhalten erfordern.

Ich musste dies implementieren, weil einige der Fragmente, die ich verwende, kleinere Ansichten haben, die ich mit der Zurück-Schaltfläche schließen möchte, wie z. B. kleine Informationsansichten, die aufpoppen, usw., aber dies ist gut für jeden, der das Verhalten der Zurück-Schaltfläche innerhalb von Fragmenten überschreiben muss.

Definieren Sie zunächst eine Schnittstelle

public interface Backable {
    boolean onBackPressed();
}

Diese Schnittstelle, die ich als Backable (ich bin ein Verfechter von Namenskonventionen), hat eine einzige Methode onBackPressed() die eine boolean Wert. Wir müssen einen booleschen Wert erzwingen, weil wir wissen müssen, ob das Drücken der Zurück-Taste das Zurück-Ereignis "absorbiert" hat. Rückgabe true bedeutet, dass dies der Fall ist, und dass keine weiteren Maßnahmen erforderlich sind, andernfalls, false besagt, dass die Standard-Rückholaktion immer noch stattfinden muss. Diese Schnittstelle sollte eine eigene Datei sein (vorzugsweise in einem separaten Paket namens interfaces ). Denken Sie daran, dass es eine gute Praxis ist, Ihre Klassen in Pakete aufzuteilen.

Zweitens: Finden Sie das oberste Fragment

Ich habe eine Methode erstellt, die die letzte Fragment Objekt im hinteren Stapel. Ich verwende Tags... wenn Sie ID's verwenden, nehmen Sie die notwendigen Änderungen vor. Ich habe diese statische Methode in einer Hilfsklasse, die sich mit Navigationszuständen usw. befasst, aber natürlich können Sie sie dort unterbringen, wo es Ihnen am besten passt. Zur Veranschaulichung habe ich meine in eine Klasse namens NavUtils .

public static Fragment getCurrentFragment(Activity activity) {
    FragmentManager fragmentManager = activity.getFragmentManager();
    if (fragmentManager.getBackStackEntryCount() > 0) {
        String lastFragmentName = fragmentManager.getBackStackEntryAt(
                fragmentManager.getBackStackEntryCount() - 1).getName();
        return fragmentManager.findFragmentByTag(lastFragmentName);
    }
    return null;
}

Vergewissern Sie sich, dass die Anzahl der zurückliegenden Stapel größer als 0 ist, sonst wird ein ArrayOutOfBoundsException könnte zur Laufzeit ausgelöst werden. Wenn er nicht größer als 0 ist, wird null zurückgegeben. Wir werden später auf einen Nullwert prüfen...

Drittens: Umsetzung in einem Fragment

Umsetzung der Backable Schnittstelle in dem Fragment, in dem Sie das Verhalten der Zurück-Schaltfläche außer Kraft setzen müssen. Fügen Sie die Implementierungsmethode hinzu.

public class SomeFragment extends Fragment implements 
        FragmentManager.OnBackStackChangedListener, Backable {

...

    @Override
    public boolean onBackPressed() {

        // Logic here...
        if (backButtonShouldNotGoBack) {
            whateverMethodYouNeed();
            return true;
        }
        return false;
    }

}

In der onBackPressed() überschreiben, setzen Sie die Logik, die Sie brauchen. Wenn Sie wollen, dass die Zurück-Taste no den Stapel zurücklegen (das Standardverhalten), zurückgeben wahr zurück, dass Ihr Back-Ereignis absorbiert wurde. Andernfalls wird false zurückgegeben.

Und schließlich, in Ihrer Aktivität...

Überschreiben Sie die onBackPressed() Methode und fügen Sie ihr diese Logik hinzu:

@Override
public void onBackPressed() {

    // Get the current fragment using the method from the second step above...
    Fragment currentFragment = NavUtils.getCurrentFragment(this);

    // Determine whether or not this fragment implements Backable
    // Do a null check just to be safe
    if (currentFragment != null && currentFragment instanceof Backable) {

        if (((Backable) currentFragment).onBackPressed()) {
            // If the onBackPressed override in your fragment 
            // did absorb the back event (returned true), return
            return;
        } else {
            // Otherwise, call the super method for the default behavior
            super.onBackPressed();
        }
    }

    // Any other logic needed...
    // call super method to be sure the back button does its thing...
    super.onBackPressed();
}

Wir holen uns das aktuelle Fragment im Backstack, dann führen wir eine Nullprüfung durch und stellen fest, ob es unsere Backable Schnittstelle. Wenn ja, stellen Sie fest, ob das Ereignis absorbiert wurde. Wenn ja, sind wir fertig mit onBackPressed() und kann zurückkehren. Andernfalls behandeln Sie es wie ein normales Zurückdrücken und rufen die Supermethode auf.

Zweite Möglichkeit, die Aktivität nicht einzubeziehen

Manchmal möchte man nicht, dass die Aktivität diese Aufgabe übernimmt, und man muss sie direkt im Fragment erledigen. Aber wer sagt, dass Sie kann nicht haben Fragmente mit einer Backpress-API? Erweitern Sie Ihr Fragment einfach um eine neue Klasse.

Erstellen Sie eine abstrakte Klasse, die Fragment erweitert und die View.OnKeyListner Schnittstelle...

import android.app.Fragment;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;

public abstract class BackableFragment extends Fragment implements View.OnKeyListener {

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        view.setFocusableInTouchMode(true);
        view.requestFocus();
        view.setOnKeyListener(this);
    }

    @Override
    public boolean onKey(View v, int keyCode, KeyEvent event) {
        if (event.getAction() == KeyEvent.ACTION_UP) {
            if (keyCode == KeyEvent.KEYCODE_BACK) {
                onBackButtonPressed();
                return true;
            }
        }

        return false;
    }

    public abstract void onBackButtonPressed();
}

Wie Sie sehen können, kann jedes Fragment, das die BackableFragment wird automatisch die Klicks mit dem View.OnKeyListener Schnittstelle. Rufen Sie einfach die abstrakte onBackButtonPressed() Methode innerhalb der implementierten onKey() Methode, bei der die Standardlogik zur Erkennung eines Drucks auf die Zurück-Taste verwendet wird. Wenn Sie andere Tastenklicks als die Rückwärtstaste registrieren müssen, müssen Sie die Methode super Methode beim Überschreiben von onKey() in Ihrem Fragment, sonst werden Sie Überschreiben Sie das Verhalten in der Abstraktion.

Einfach zu verwenden, einfach erweitern und implementieren:

public class FragmentChannels extends BackableFragment {

    ...

    @Override
    public void onBackButtonPressed() {
        if (doTheThingRequiringBackButtonOverride) {
            // do the thing
        } else {
            getActivity().onBackPressed();
        }
    }

    ...
}

Da die onBackButtonPressed() Methode in der Superklasse abstrakt ist, müssen Sie, sobald Sie erweitern, die onBackButtonPressed() . Sie gibt zurück void weil es nur eine Aktion innerhalb der Fragmentklasse ausführen muss und die Absorption des Drucks nicht an die Aktivität zurückgeben muss. Vergewissern Sie sich Sie rufen die Aktivität auf onBackPressed() Methode, wenn das, was Sie mit der Zurück-Schaltfläche tun, keine Bearbeitung erfordert, sonst wird die Zurück-Schaltfläche deaktiviert... und das wollen Sie nicht!

Vorbehalte Wie Sie sehen können, wird dadurch der Key Listener auf die Root-Ansicht des Fragments gesetzt, und wir müssen ihn fokussieren. Wenn in Ihrem Fragment, das diese Klasse erweitert (oder andere innere Fragmente oder Ansichten, die dasselbe haben), Bearbeitungstexte beteiligt sind (oder andere fokusraubende Ansichten), müssen Sie das separat behandeln. Es gibt einen guten Artikel über Erweiterung eines EditTextes den Fokus auf eine Rückenpresse zu verlieren.

Ich hoffe, jemand findet dies nützlich. Viel Spaß beim Codieren.

16voto

protanvir993 Punkte 2241

In Kotlin ist es viel einfacher.

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, object : OnBackPressedCallback(true) {
        override fun handleOnBackPressed() {
            //
        }
    })
}

15voto

IdoT Punkte 2725

Die Lösung ist einfach:

  1. Wenn Sie eine Basisfragmentklasse haben, die von allen Fragmenten erweitert wird, dann fügen Sie diesen Code zu ihrer Klasse hinzu, ansonsten erstellen Sie eine solche Basisfragmentklasse

    /*

    • called when on back pressed to the current fragment that is returned */ public void onBackPressed() { // add code in super class when override }
  2. Überschreiben Sie in Ihrer Activity-Klasse onBackPressed wie folgt:

    private BaseFragment _currentFragment;

    @Override public void onBackPressed() { super.onBackPressed(); _currentFragment.onBackPressed(); }

  3. Fügen Sie in Ihrer Fragment-Klasse den gewünschten Code ein:

    @Override public void onBackPressed() { setUpTitle(); }

11voto

林奕忠 Punkte 666

onBackPressed() das Fragment von der Aktivität zu trennen.

Laut der Antwort von @Sterling Diaz denke ich, dass er Recht hat. ABER einige Situationen werden falsch sein. (z.B. Bildschirm rotieren)

Ich denke, wir könnten feststellen, ob isRemoving() um Ziele zu erreichen.

Sie können es schreiben an onDetach() o onDestroyView() . Es ist Arbeit.

@Override
public void onDetach() {
    super.onDetach();
    if(isRemoving()){
        // onBackPressed()
    }
}

@Override
public void onDestroyView() {
    super.onDestroyView();
    if(isRemoving()){
        // onBackPressed()
    }
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X