puisque cette question et certaines des réponses ont plus de cinq ans, permettez-moi de partager ma solution. Ceci est un suivi et une modernisation de la réponse de @oyenigun
MISE À JOUR:
À Au bas de cet article, j'ai ajouté une implémentation alternative utilisant une extension de fragment abstraite qui n'impliquera pas du tout l'activité, ce qui serait utile pour toute personne ayant une hiérarchie de fragments plus complexe impliquant des fragments imbriqués qui nécessitent un comportement arrière différent.
J'avais besoin de l'implémenter car certains des fragments que j'utilise ont des vues plus petites que je voudrais ignorer avec le bouton de retour, telles que les petites vues d'informations qui apparaissent, etc., mais cela est bon pour tous ceux qui ont besoin de remplacer le comportement de le bouton de retour à l'intérieur des fragments.
Tout d'abord, définissez une interface
public interface Backable {
boolean onBackPressed();
}
Cette interface, que j'appelle Backable
(je suis un adepte des conventions de dénomination), a une seule méthode onBackPressed()
qui doit retourner une boolean
valeur. Nous devons appliquer une valeur booléenne, car nous devrons savoir si la pression sur le bouton de retour a «absorbé» l'événement de retour. Renvoyer true
signifie que c'est le cas, et qu'aucune action supplémentaire n'est nécessaire, sinon, false
indique que l'action de retour par défaut doit toujours avoir lieu. Cette interface doit être son propre fichier (de préférence dans un package distinct nommé interfaces
). N'oubliez pas que la séparation de vos classes en packages est une bonne pratique.
Deuxièmement, trouvez le fragment supérieur
J'ai créé une méthode qui renvoie le dernier Fragment
objet de la pile arrière. J'utilise des balises ... si vous utilisez des identifiants, apportez les modifications nécessaires. J'ai cette méthode statique dans une classe utilitaire qui traite des états de navigation, etc ... mais bien sûr, mettez-la là où elle vous convient le mieux. Pour l'édification, j'ai mis le mien dans une classe appelée 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;
}
Assurez-vous que le nombre de piles de retour est supérieur à 0, sinon un ArrayOutOfBoundsException
pourrait être lancé lors de l'exécution. S'il n'est pas supérieur à 0, retournez null. Nous vérifierons une valeur nulle plus tard ...
Troisièmement, implémentez dans un fragment
Implémentez l' Backable
interface dans le fragment dans lequel vous devez remplacer le comportement du bouton de retour. Ajoutez la méthode d'implémentation.
public class SomeFragment extends Fragment implements
FragmentManager.OnBackStackChangedListener, Backable {
...
@Override
public boolean onBackPressed() {
// Logic here...
if (backButtonShouldNotGoBack) {
whateverMethodYouNeed();
return true;
}
return false;
}
}
Dans le onBackPressed()
remplacement, mettez la logique dont vous avez besoin. Si vous souhaitez que le bouton Précédent ne fasse pas apparaître la pile arrière (comportement par défaut), retournez true , que votre événement de retour a été absorbé. Sinon, retournez false.
Enfin, dans votre activité ...
Redéfinissez la onBackPressed()
méthode et ajoutez-y cette logique:
@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();
}
Nous obtenons le fragment actuel dans la pile arrière, puis nous effectuons une vérification nulle et déterminons s'il implémente notre Backable
interface. Si c'est le cas, déterminez si l'événement a été absorbé. Si oui, nous en avons fini aveconBackPressed()
et pouvons revenir. Sinon, traitez-le comme une contre-pression normale et appelez la super méthode.
Deuxième option pour ne pas impliquer l'activité
Parfois, vous ne voulez pas que l'activité gère cela du tout, et vous devez le gérer directement dans le fragment. Mais qui dit que tu ne peux pas avoir de fragments avec une API de contre-presse? Étendez simplement votre fragment à une nouvelle classe.
Créez une classe abstraite qui étend Fragment et implémente l' View.OnKeyListner
interface ...
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();
}
Comme vous pouvez le voir, tout fragment qui se prolonge BackableFragment
capturera automatiquement les clics en arrière en utilisant l' View.OnKeyListener
interface. Appelez simplement la onBackButtonPressed()
méthode abstraite à partir de la onKey()
méthode implémentée en utilisant la logique standard pour discerner une pression sur le bouton de retour. Si vous devez enregistrer des clics sur les touches autres que le bouton Précédent, assurez-vous simplement d'appeler la super
méthode lors de la substitutiononKey()
dans votre fragment, sinon vous remplacerez le comportement dans l'abstraction.
Simple à utiliser, il suffit d'étendre et de mettre en œuvre:
public class FragmentChannels extends BackableFragment {
...
@Override
public void onBackButtonPressed() {
if (doTheThingRequiringBackButtonOverride) {
// do the thing
} else {
getActivity().onBackPressed();
}
}
...
}
Puisque la onBackButtonPressed()
méthode dans la super classe est abstraite, une fois que vous étendez, vous devez implémenter onBackButtonPressed()
. Il revient void
car il a juste besoin d'effectuer une action au sein de la classe de fragments et n'a pas besoin de relayer l'absorption de la presse à l'activité. Assurez- vous d'appeler la onBackPressed()
méthode Activity si tout ce que vous faites avec le bouton de retour ne nécessite pas de manipulation, sinon le bouton de retour sera désactivé ... et vous ne le voulez pas!
Avertissements
Comme vous pouvez le voir, cela définit l'écouteur clé sur la vue racine du fragment, et nous devons le concentrer. S'il y a des textes d'édition impliqués (ou toute autre vue volant le focus) dans votre fragment qui étend cette classe, (ou d'autres fragments internes ou vues qui ont la même), vous devrez gérer cela séparément. Il y a un bon article sur l' extension d'un EditText pour perdre le focus sur une presse arrière.
J'espère que quelqu'un trouve cela utile. Codage heureux.