poiché questa domanda e alcune delle risposte hanno più di cinque anni, vorrei condividere la mia soluzione. Questo è un seguito e una modernizzazione della risposta di @oyenigun
AGGIORNARE:
Alla fine di questo articolo, ho aggiunto un'implementazione alternativa usando un'estensione astratta del frammento che non coinvolgerà affatto l'attività, che sarebbe utile per chiunque abbia una gerarchia di frammenti più complessa che coinvolge frammenti nidificati che richiedono un diverso comportamento alla schiena.
Avevo bisogno di implementarlo perché alcuni dei frammenti che utilizzo hanno viste più piccole che vorrei eliminare con il pulsante Indietro, come piccole viste di informazioni che compaiono, ecc., Ma questo è utile per chiunque abbia bisogno di ignorare il comportamento di il pulsante indietro all'interno di frammenti.
Innanzitutto, definire un'interfaccia
public interface Backable {
boolean onBackPressed();
}
Questa interfaccia, che io chiamo Backable
(sono un pignolo per le convenzioni di denominazione), ha un solo metodo onBackPressed()
che deve restituire un boolean
valore. Dobbiamo imporre un valore booleano perché dovremo sapere se la pressione del pulsante Indietro ha "assorbito" l'evento back. Restituire true
significa che lo è, e non sono necessarie ulteriori azioni, altrimenti, false
afferma che l'azione di ritorno predefinita deve ancora aver luogo. Questa interfaccia dovrebbe essere il proprio file (preferibilmente in un pacchetto separato chiamato interfaces
). Ricorda, separare le tue classi in pacchetti è una buona pratica.
Secondo, trova il frammento superiore
Ho creato un metodo che restituisce l'ultimo Fragment
oggetto nello stack posteriore. Uso i tag ... se usi gli ID, apporto le modifiche necessarie. Ho questo metodo statico in una classe di utilità che si occupa di stati di navigazione, ecc ... ma, naturalmente, lo metto dove ti si addice meglio. Per l'edificazione, ho messo il mio in una classe chiamata 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;
}
Assicurarsi che il conteggio dello stack posteriore sia maggiore di 0, altrimenti ArrayOutOfBoundsException
potrebbe essere lanciato in fase di esecuzione. Se non è maggiore di 0, restituisce null. Verificheremo un valore null più tardi ...
In terzo luogo, implementare in un frammento
Implementare l' Backable
interfaccia in qualunque frammento in cui è necessario sovrascrivere il comportamento del pulsante Indietro. Aggiungi il metodo di implementazione.
public class SomeFragment extends Fragment implements
FragmentManager.OnBackStackChangedListener, Backable {
...
@Override
public boolean onBackPressed() {
// Logic here...
if (backButtonShouldNotGoBack) {
whateverMethodYouNeed();
return true;
}
return false;
}
}
Nella onBackPressed()
sostituzione, inserisci la logica di cui hai bisogno. Se si desidera che il pulsante Indietro non visualizzi lo stack posteriore (comportamento predefinito), tornare true che l'evento back è stato assorbito. Altrimenti, restituisci false.
Infine, nella tua attività ...
Sostituisci il onBackPressed()
metodo e aggiungi questa logica ad esso:
@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();
}
Otteniamo il frammento corrente nello stack posteriore, quindi eseguiamo un controllo nullo e determiniamo se implementa la nostra Backable
interfaccia. In tal caso, determinare se l'evento è stato assorbito. In tal caso, abbiamo terminato onBackPressed()
e possiamo tornare. Altrimenti, trattalo come una normale back press e chiama il metodo super.
Seconda opzione per non coinvolgere l'attività
A volte, non vuoi che l'Attività gestisca questo e devi gestirla direttamente all'interno del frammento. Ma chi dice che non puoi avere frammenti con un'API di back press? Estendi il tuo frammento a una nuova classe.
Crea una classe astratta che estende il frammento e implementa l' View.OnKeyListner
interfaccia ...
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();
}
Come puoi vedere, qualsiasi frammento che si estende BackableFragment
acquisirà automaticamente i clic indietro utilizzando l' View.OnKeyListener
interfaccia. Basta chiamare il onBackButtonPressed()
metodo astratto dall'interno del onKey()
metodo implementato utilizzando la logica standard per discernere una pressione del pulsante Indietro. Se devi registrare i clic sui tasti oltre al pulsante Indietro, assicurati di chiamare il super
metodo quando esegui l'override onKey()
nel frammento, altrimenti eseguirai l' override il comportamento nell'astrazione.
Semplice da usare, basta estendere e implementare:
public class FragmentChannels extends BackableFragment {
...
@Override
public void onBackButtonPressed() {
if (doTheThingRequiringBackButtonOverride) {
// do the thing
} else {
getActivity().onBackPressed();
}
}
...
}
Poiché il onBackButtonPressed()
metodo nella superclasse è astratto, una volta esteso è necessario implementarlo onBackButtonPressed()
. Ritorna void
perché deve solo eseguire un'azione all'interno della classe di frammenti e non deve ritrasmettere l'Assorbimento della pressa all'attività. Assicurati di chiamare il onBackPressed()
metodo Activity se qualsiasi cosa tu stia facendo con il pulsante Indietro non richiede gestione, altrimenti il pulsante Indietro sarà disabilitato ... e non lo vuoi!
Avvertenze
Come puoi vedere, questo imposta l'ascoltatore chiave sulla vista radice del frammento e dovremo focalizzarlo. Se ci sono testi di modifica coinvolti (o qualsiasi altra vista che ruba il focus) nel tuo frammento che estende questa classe (o altri frammenti o viste interni che hanno lo stesso), dovrai gestirlo separatamente. C'è un buon articolo sull'estensione di un EditText per perdere la concentrazione su una stampa precedente.
Spero che qualcuno lo trovi utile. Buona codifica.