web-dev-qa-db-fra.com

Comment implémenter onBackPressed () dans Fragments?

Existe-t-il un moyen d'implémenter onBackPressed() dans un fragment Android similaire à celui utilisé dans Android Activity?

Comme le cycle de vie d'un fragment n'a pas onBackPressed(). Existe-t-il une autre méthode pour surpasser onBackPressed() dans Android 3.0 fragments?

404

J'ai résolu de cette façon remplacer onBackPressed dans l'activité. Tous les FragmentTransaction sont addToBackStack avant commit:

@Override
public void onBackPressed() {

    int count = getSupportFragmentManager().getBackStackEntryCount();

    if (count == 0) {
        super.onBackPressed();
        //additional code
    } else {
        getSupportFragmentManager().popBackStack();
    }

}
280
Hw.Master

Je pense que la meilleure solution est

SOLUTION Java

Créer une interface simple:

public interface IOnBackPressed {
    /**
     * If you return true the back press will not be taken into account, otherwise the activity will act naturally
     * @return true if your processing has priority if not false
     */
    boolean onBackPressed();
}

Et dans ton activité

public class MyActivity extends Activity {
    @Override public void onBackPressed() {
    Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.main_container);
       if (!(fragment instanceof IOnBackPressed) || !((IOnBackPressed) fragment).onBackPressed()) {
          super.onBackPressed();
       }
    } ...
}

Enfin dans votre fragment:

public class MyFragment extends Fragment implements IOnBackPressed{
   @Override
   public boolean onBackPressed() {
       if (myCondition) {
            //action not popBackStack
            return true; 
        } else {
            return false;
        }
    }
}

KOTLIN SOLUTION

1 - Créer une interface

interface IOnBackPressed {
    fun onBackPressed(): Boolean
}

2 - Préparez votre activité

class MyActivity : AppCompatActivity() {
    override fun onBackPressed() {
        val fragment =
            this.supportFragmentManager.findFragmentById(R.id.main_container)
        (fragment as? IOnBackPressed)?.onBackPressed()?.not()?.let {
            super.onBackPressed()
        }
    }
}

3 - Implémenter dans votre fragment cible

class MyFragment : Fragment(), IOnBackPressed {
    override fun onBackPressed(): Boolean {
        return if (myCondition) {
            //action not popBackStack
            true
        } else {
            false
        }
    }
}
119
Maxime Jallu

Selon la réponse de @HaMMeRed, voici comment un pseudocode devrait fonctionner. Disons que votre activité principale s'appelle BaseActivity et comporte des fragments enfant (comme dans l'exemple de lib SlidingMenu lib). Voici les étapes:

Nous avons d’abord besoin de créer une interface et une classe qui implémente son interface pour avoir une méthode générique

  1. Créer une interface de classe OnBackPressedListener

    public interface OnBackPressedListener {
        public void doBack();
    }
    
  2. Créer une classe qui implémente les compétences de OnBackPressedListener

    public class BaseBackPressedListener implements OnBackPressedListener {
        private final FragmentActivity activity;
    
        public BaseBackPressedListener(FragmentActivity activity) {
            this.activity = activity;
        }
    
        @Override
        public void doBack() {
            activity.getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
        }
    }
    
  3. Depuis, nous allons travailler sur notre code BaseActivity et ses fragments

  4. Créez un auditeur privé au-dessus de votre classe BaseActivity

    protected OnBackPressedListener onBackPressedListener;
    
  5. méthode create pour définir le programme d'écoute dans BaseActivity

    public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
        this.onBackPressedListener = onBackPressedListener;
    }
    
  6. en dérogation onBackPressed implémenter quelque chose comme ça

    @Override
    public void onBackPressed() {
        if (onBackPressedListener != null)
            onBackPressedListener.doBack();
        else
            super.onBackPressed();
    
  7. dans votre fragment dans onCreateView vous devriez ajouter notre auditeur

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        activity = getActivity();
    
        ((BaseActivity)activity).setOnBackPressedListener(new BaseBackPressedListener(activity));
    
        View view = ... ;
    //stuff with view
    
        return view;
    }
    

Voila, maintenant quand vous cliquez en arrière dans le fragment, vous devriez attraper votre méthode personnalisée sur le dos.

92
deadfish

Cela a fonctionné pour moi: https://stackoverflow.com/a/27145007/3934111

@Override
public void onResume() {
    super.onResume();

    if(getView() == null){
        return;
    }

    getView().setFocusableInTouchMode(true);
    getView().requestFocus();
    getView().setOnKeyListener(new View.OnKeyListener() {
        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {

            if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK){
                // handle back button's click listener
                return true;
            }
            return false;
        }
    });
}
78
Rodrigo Rodrigues

Si vous souhaitez ce type de fonctionnalité, vous devez la remplacer dans votre activité, puis ajouter une interface YourBackPressed à tous vos fragments, que vous appelez sur le fragment approprié chaque fois que vous appuyez sur le bouton Précédent.

Edit: J'aimerais ajouter ma réponse précédente.

Si je devais le faire aujourd'hui, j'utiliserais une émission, ou éventuellement une émission ordonnée, si je m'attendais à ce que d'autres panneaux se mettent à jour à l'unisson avec le panneau de contenu principal/principal.

LocalBroadcastManager dans la bibliothèque de support technique peut vous aider. Il vous suffit d'envoyer la diffusion au format onBackPressed et de vous abonner aux fragments concernés. Je pense que la messagerie est une mise en œuvre plus découplée et qu'elle évoluerait mieux. Ce serait donc ma recommandation officielle pour la mise en œuvre maintenant. Utilisez simplement l’action Intent comme filtre pour votre message. envoyez votre ACTION_BACK_PRESSED nouvellement créé, envoyez-le depuis votre activité et écoutez-le dans les fragments appropriés.

64
HaMMeReD

Rien de tout cela n’est facile à mettre en œuvre et ne fonctionnera pas de manière optimale.

Les fragments ont une méthode appelée onDetach qui fera le travail.

@Override
    public void onDetach() {
        super.onDetach();
        PUT YOUR CODE HERE
    }

CECI FAIT LE TRAVAIL.

46
Sterling Diaz

Ajoutez simplement addToBackStack pendant que vous effectuez la transition entre vos fragments, comme ci-dessous:

fragmentManager.beginTransaction().replace(R.id.content_frame,fragment).addToBackStack("tag").commit();

si vous écrivez addToBackStack(null), il le gérera tout seul, mais si vous attribuez une balise, vous devez le manipuler manuellement.

24
Rudi

comme cette question et certaines des réponses ont plus de cinq ans, laissez-moi partager ma solution. Ceci est un suivi et une modernisation de la réponse de @oyenigun

UPDATE: Au bas de cet article, j'ai ajouté une implémentation alternative utilisant une extension de fragment abstraite qui n'impliquerait pas l'activité du tout, qui serait utile pour toute personne ayant une hiérarchie de fragments plus complexe impliquant des fragments imbriqués nécessitant un comportement arrière différent.

Je devais mettre cela en œuvre car certains fragments que j’utilise ont des vues plus petites que je voudrais rejeter avec le bouton Précédent, telles que de petites vues d’informations qui s’ouvrent, etc. le bouton de retour à l'intérieur des fragments.

Définissez d'abord une interface

public interface Backable {
    boolean onBackPressed();
}

Cette interface, que j’appelle Backable (je ne respecte pas les conventions de nommage), a une seule méthode onBackPressed() qui doit renvoyer une valeur boolean. Nous devons imposer une valeur booléenne, car nous devrons savoir si la pression du bouton Précédent a "absorbé" l'événement Back. Retourner 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 paquet séparé nommé interfaces). N'oubliez pas que séparer 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 objet Fragment 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 d'utilitaire qui traite des états de navigation, etc., mais bien sûr, mettez-la où cela 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 une ArrayOutOfBoundsException pourrait être émise au moment de l'exécution. Si ce n'est pas supérieur à 0, retourne null. Nous vérifierons une valeur nulle plus tard ...

Troisièmement, implémenter dans un fragment

Implémentez l'interface Backable dans le fragment où vous devez remplacer le comportement du bouton Précédent. 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 la substitution onBackPressed(), mettez la logique dont vous avez besoin. Si vous voulez que le bouton Précédent ne saute pas , la pile arrière (le comportement par défaut), renvoie true , que votre événement de retour a été absorbé. Sinon, retourne false.

Enfin, dans votre activité ...

Remplacez la méthode onBackPressed() et ajoutez-lui 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 de null et déterminons s'il implémente notre interface Backable. Si c'est le cas, déterminez si l'événement a été absorbé. Si c'est le cas, nous en avons terminé avec onBackPressed() et nous pouvons revenir. Sinon, traitez-le comme une presse 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 a dit que vous ne pouvez pas avoir des fragments avec une API de presse arrière? Étendez simplement votre fragment dans une nouvelle classe.

Créez une classe abstraite qui étend Fragment et implémente l'interface View.OnKeyListner ...

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 constater, tout fragment qui s'étend BackableFragment capturera automatiquement les clics retour à l'aide de l'interface View.OnKeyListener. Appelez simplement la méthode abstraite onBackButtonPressed() à partir de la méthode implémentée onKey() en utilisant la logique standard pour discerner une pression sur le bouton Précédent. Si vous devez enregistrer des clics sur les touches autres que le bouton Précédent, veillez simplement à appeler la méthode super lorsque vous écrasez onKey() dans votre fragment. Sinon, vous écraserez le comportement dans l'abstraction.

Simple à utiliser, il suffit d'étendre et d'implémenter:

public class FragmentChannels extends BackableFragment {

    ...

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

    ...
}

Comme la méthode onBackButtonPressed() de la super-classe est abstraite, vous devez implémenter onBackButtonPressed() une fois que vous étendez. Il retourne void car il lui suffit d'exécuter une action dans la classe fragment et n'a pas besoin de relayer l'absorption de la presse à l'activité. Assurez-vous que vous appelez la méthode Activity onBackPressed() si ce que vous faites avec le bouton Précédent ne nécessite aucune manipulation. Sinon, le bouton retour sera désactivé ... et vous ne voulez pas ça!

Mises en garde Comme vous pouvez le constater, l'écouteur de clé est défini sur la vue racine du fragment et nous devons le cibler. S'il y a des textes de modification impliqués (ou toute autre vue voleuse de focus) dans votre fragment qui étend cette classe (ou d'autres fragments internes ou vues ayant la même chose), vous devrez gérer cela séparément. Il existe un bon article sur extension d'un EditText pour perdre le focus sur une presse arrière.

J'espère que quelqu'un trouvera cela utile. Bonne codage.

20
mwieczorek

La solution est simple:

1) Si vous avez une classe de fragments de base que tous les fragments étendent, ajoutez ce code à sa classe, sinon créez une telle classe de fragments de base

 /* 
 * called when on back pressed to the current fragment that is returned
 */
 public void onBackPressed()
 {
    // add code in super class when override
 }

2) Dans votre classe d'activité, remplacez onBackPressed comme suit:

private BaseFragment _currentFragment;

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

3) Dans votre classe Fragment, ajoutez le code souhaité:

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

onBackPressed() provoque la séparation du fragment de l'activité.

Selon la réponse de @Sterling Diaz, je pense qu'il a raison. MAIS une situation sera fausse. (ex. Rotate Screen)

Je pense donc que nous pourrions détecter si isRemoving() doit atteindre ses objectifs.

Vous pouvez l'écrire sous onDetach() ou onDestroyView(). C'est du travail.

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

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

Ceci est juste un petit code qui fera l'affaire:

 getActivity().onBackPressed();

J'espère que ça aide quelqu'un :)

8
Shahid Sarwar

Eh bien je l'ai fait comme ça, et ça marche pour moi

Interface simple

FragmentOnBackClickInterface.Java

public interface FragmentOnBackClickInterface {
    void onClick();
}

Exemple d'implémentation

MyFragment.Java

public class MyFragment extends Fragment implements FragmentOnBackClickInterface {

// other stuff

public void onClick() {
       // what you want to call onBackPressed?
}

puis il suffit de remplacer onBackPressed dans l'activité

    @Override
public void onBackPressed() {
    int count = getSupportFragmentManager().getBackStackEntryCount();
    List<Fragment> frags = getSupportFragmentManager().getFragments();
    Fragment lastFrag = getLastNotNull(frags);
    //nothing else in back stack || nothing in back stack is instance of our interface
    if (count == 0 || !(lastFrag instanceof FragmentOnBackClickInterface)) {
        super.onBackPressed();
    } else {
        ((FragmentOnBackClickInterface) lastFrag).onClick();
    }
}

private Fragment getLastNotNull(List<Fragment> list){
    for (int i= list.size()-1;i>=0;i--){
        Fragment frag = list.get(i);
        if (frag != null){
            return frag;
        }
    }
    return null;
}
7
Błażej

Vous devriez ajouter une interface à votre projet comme ci-dessous;

public interface OnBackPressed {

     void onBackPressed();
}

Et ensuite, vous devez implémenter cette interface sur votre fragment;

public class SampleFragment extends Fragment implements OnBackPressed {

    @Override
    public void onBackPressed() {
        //on Back Pressed
    }

}

Et vous pouvez déclencher cet événement onBackPressed dans vos activités avec l'événement onBackPressed comme ci-dessous;

public class MainActivity extends AppCompatActivity {
       @Override
        public void onBackPressed() {
                Fragment currentFragment = getSupportFragmentManager().getFragments().get(getSupportFragmentManager().getBackStackEntryCount() - 1);
                if (currentFragment instanceof OnBackPressed) {  
                    ((OnBackPressed) currentFragment).onBackPressed();
                }
                super.onBackPressed();
        }
}
7
oyenigun

c'est ma solution:

dans MyActivity.Java:

public interface OnBackClickListener {
        boolean onBackClick();
    }

    private OnBackClickListener onBackClickListener;

public void setOnBackClickListener(OnBackClickListener onBackClickListener) {
        this.onBackClickListener = onBackClickListener;
    }

@Override
    public void onBackPressed() {
        if (onBackClickListener != null && onBackClickListener.onBackClick()) {
            return;
        }
        super.onBackPressed();
    }

et dans Fragment:

((MyActivity) getActivity()).setOnBackClickListener(new MyActivity.OnBackClickListener() {
    @Override
    public boolean onBackClick() {
        if (condition) {
            return false;
        }

        // some codes

        return true;
    }
});
6
Hamidreza Samadi

Si vous utilisez EventBus, c'est probablement une solution beaucoup plus simple:

Dans votre fragment:

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    EventBus.getDefault().register(this);
}

@Override
public void onDetach() {
    super.onDetach();
    EventBus.getDefault().unregister(this);
}


// This method will be called when a MessageEvent is posted
public void onEvent(BackPressedMessage type){
    getSupportFragmentManager().popBackStack();
}

et dans votre classe d'activité, vous pouvez définir:

@Override
public void onStart() {
    super.onStart();
    EventBus.getDefault().register(this);
}

@Override
public void onStop() {
    EventBus.getDefault().unregister(this);
    super.onStop();
}

// This method will be called when a MessageEvent is posted
public void onEvent(BackPressedMessage type){
    super.onBackPressed();
}

@Override
public void onBackPressed() {
    EventBus.getDefault().post(new BackPressedMessage(true));
}

BackPressedMessage.Java est juste un objet POJO

Ceci est super propre et il n'y a pas de problèmes d'interface/implémentation.

6
Akshat

Que diriez-vous d'utiliser onDestroyView ()?

@Override
public void onDestroyView() {
    super.onDestroyView();
}
5
@Override
public void onResume() {
    super.onResume();

    getView().setFocusableInTouchMode(true);
    getView().requestFocus();
    getView().setOnKeyListener(new View.OnKeyListener() {
        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {
            if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
                // handle back button
                replaceFragmentToBackStack(getActivity(), WelcomeFragment.newInstance(bundle), tags);

                return true;
            }

            return false;
        }
    });
}
4
Gururaj Hosamani

Selon les notes de version d'AndroidX , androidx.activity 1.0.0-alpha01 est publié et introduit ComponentActivity, une nouvelle classe de base de FragmentActivity et AppCompatActivity existants. Et cette version nous apporte une nouvelle fonctionnalité:

Vous pouvez maintenant enregistrer un OnBackPressedCallback via addOnBackPressedCallback pour recevoir des rappels onBackPressed() sans avoir à remplacer la méthode dans votre activité.

3
TonnyL

Il suffit de suivre ces étapes:

Toujours en ajoutant un fragment,

fragmentTransaction.add(R.id.fragment_container, detail_fragment, "Fragment_tag").addToBackStack(null).commit();

Ensuite, dans l'activité principale, remplacez onBackPressed()

if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
    getSupportFragmentManager().popBackStack();
} else {
    finish();
}

Pour gérer le bouton de retour dans votre application,

Fragment f = getActivity().getSupportFragmentManager().findFragmentByTag("Fragment_tag");
if (f instanceof FragmentName) {
    if (f != null) 
        getActivity().getSupportFragmentManager().beginTransaction().remove(f).commit()               
}

C'est ça!

3
Divya

Dans le cycle de vie de l'activité, le bouton toujours Android précédent traite des transactions FragmentManager lorsque nous utilisons FragmentActivity ou AppCompatActivity.

Pour gérer le backstack, nous n’avons pas besoin de gérer son décompte ou de marquer quoi que ce soit, mais nous devons rester concentrés lors de l’ajout ou du remplacement d’un fragment. S'il vous plaît trouver les extraits suivants pour gérer les cas de bouton de retour,

    public void replaceFragment(Fragment fragment) {

        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        if (!(fragment instanceof HomeFragment)) {
            transaction.addToBackStack(null);
        }
        transaction.replace(R.id.activity_menu_fragment_container, fragment).commit();
    }

Ici, je n’ajouterai pas de pile de retour pour mon fragment home, car c’est la page d’accueil de mon application. Si vous ajoutez addToBackStack à HomeFragment, l'application attendra de supprimer toutes les alarmes de manière active, nous obtiendrons alors un écran vide. Je garde donc la condition suivante,

if (!(fragment instanceof HomeFragment)) {
            transaction.addToBackStack(null);
}

Maintenant, vous pouvez voir le fragment ajouté précédemment sur acitvity et l'application se fermera lorsque vous atteindrez HomeFragment. vous pouvez également consulter les extraits suivants.

@Override
public void onBackPressed() {

    if (mDrawerLayout.isDrawerOpen(Gravity.LEFT)) {
        closeDrawer();
    } else {
        super.onBackPressed();
    }
}
3
Deva

Très courte et douce réponse:

getActivity().onBackPressed();

Explication de tout le scénario de mon cas:

J'ai FragmentA dans MainActivity, j'ouvre FragmentB à partir de FragmentA (FragmentB est un fragment enfant ou imbriqué de FragmentA).

 Fragment duedateFrag = new FragmentB();
 FragmentTransaction ft  = getFragmentManager().beginTransaction();
 ft.replace(R.id.container_body, duedateFrag);
 ft.addToBackStack(null);
 ft.commit();

Maintenant, si vous voulez aller à FragmentA à partir de FragmentB, vous pouvez simplement mettre getActivity().onBackPressed(); dans FragmentB.

3
Parsania Hardik

N'appliquez pas la méthode ft.addToBackStack () afin que, lorsque vous avez appuyé sur le bouton Précédent, votre activité soit terminée.

proAddAccount = new ProfileAddAccount();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, proAddAccount);
//fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
3
Muhammad Aamir Ali

Meilleure solution,

import Android.support.v4.app.Fragment;
import Android.support.v4.app.FragmentManager;
import Android.support.v7.app.AppCompatActivity;

public class BaseActivity extends AppCompatActivity {
    @Override
    public void onBackPressed() {

        FragmentManager fm = getSupportFragmentManager();
        for (Fragment frag : fm.getFragments()) {
            if (frag == null) {
                super.onBackPressed();
                finish();
                return;
            }
            if (frag.isVisible()) {
                FragmentManager childFm = frag.getChildFragmentManager();
                if (childFm.getFragments() == null) {
                    super.onBackPressed();
                    finish();
                    return;
                }
                if (childFm.getBackStackEntryCount() > 0) {
                    childFm.popBackStack();
                    return;
                }
                else {

                    fm.popBackStack();
                    if (fm.getFragments().size() <= 1) {
                        finish();
                    }
                    return;
                }

            }
        }
    }
}
2
Shervin Gharib

Faites-le simplement dans onKeyUp ():

@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {

    if (keyCode == KeyEvent.KEYCODE_BACK) {
        // do something
        return true;  // return true if back handled, false otherwise
    }

    return super.onKeyUp(keyCode, event);
}
2
b0b

Vous pouvez enregistrer un fragment d’activité pour gérer la presse arrière:

interface BackPressRegistrar {
    fun registerHandler(handler: BackPressHandler)
    fun unregisterHandler(handler: BackPressHandler)
}

interface BackPressHandler {
    fun onBackPressed(): Boolean
}

tilisation:

En fragment:

private val backPressHandler = object : BackPressHandler {
    override fun onBackPressed(): Boolean {
        showClosingWarning()
        return false
    }
}

override fun onResume() {
    super.onResume()
    (activity as? BackPressRegistrar)?.registerHandler(backPressHandler)
}

override fun onStop() {
    (activity as? BackPressRegistrar)?.unregisterHandler(backPressHandler)
    super.onStop()
}

En activité:

class MainActivity : AppCompatActivity(), BackPressRegistrar {


    private var registeredHandler: BackPressHandler? = null
    override fun registerHandler(handler: BackPressHandler) { registeredHandler = handler }
    override fun unregisterHandler(handler: BackPressHandler) { registeredHandler = null }

    override fun onBackPressed() {
        if (registeredHandler?.onBackPressed() != false) super.onBackPressed()
    }
}
2
Francis

Je sais que c'est trop tard, mais j'ai eu le même problème la semaine dernière. Aucune des réponses ne m'a aidé. Je jouais alors avec le code et cela fonctionnait, car j'avais déjà ajouté les fragments.

Dans votre activité, définissez un OnPageChangeListener pour le ViewPager afin que vous sachiez à quel moment l'utilisateur se trouve dans la deuxième activité. S'il est dans la deuxième activité, créez un booléen true comme suit:

    mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
    // Set up the ViewPager with the sections adapter.
    mViewPager = (ViewPager) findViewById(R.id.pager);
    mViewPager.setAdapter(mSectionsPagerAdapter);
    mViewPager.setCurrentItem(0);
    mViewPager.addOnPageChangeListener(new OnPageChangeListener() {

        @Override
        public void onPageSelected(int position) {
            // TODO Auto-generated method stub
                mSectionsPagerAdapter.instantiateItem(mViewPager, position);
                if(position == 1)
                    inAnalytics = true;
                else if(position == 0)
                    inAnalytics = false;
        }

        @Override
        public void onPageScrolled(int position, float arg1, int arg2) {
            // TODO Auto-generated method stub
        }

        @Override
        public void onPageScrollStateChanged(int arg0) {
            // TODO Auto-generated method stub

        }
    });

Recherchez maintenant le booléen chaque fois que vous appuyez sur le bouton Précédent et définissez l'élément actuel sur votre premier fragment:

@Override
public void onBackPressed() {
    if(inAnalytics)
        mViewPager.setCurrentItem(0, true);
    else 
        super.onBackPressed();
}
1
zeeshan khan

Ok les gars, j'ai finalement trouvé une bonne solution.

Dans votre activité onCreate () hébergeant vos fragments, ajoutez un auditeur de changement de pile comme ceci:

    fragmentManager.addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
        @Override
        public void onBackStackChanged() {
            List<Fragment> f = fragmentManager.getFragments();
            //List<Fragment> f only returns one value
            Fragment frag = f.get(0);
            currentFragment = frag.getClass().getSimpleName();
        }
    });

(L'ajout de mon fragmenManager est également déclaré dans les activités O Maintenant, chaque fois que vous modifiez un fragment, le fragment actuel devient le nom du fragment actuel. Dans les activités onBackPressed (), vous pouvez également contrôler les actions de votre bouton Précédent:

    @Override
    public void onBackPressed() {

    switch (currentFragment) {
        case "FragmentOne":
            // your code here
            return;
        case "FragmentTwo":
            // your code here
            return;
        default:
            fragmentManager.popBackStack();
            // default action for any other fragment (return to previous)
    }

}

Je peux confirmer que cette méthode fonctionne pour moi.

1
Haider Malik

C’est simple si vous avez une activité A et que vous créez 3 fragments tels que B, C et D. Maintenant, si vous êtes dans le fragment B ou C et onBackPressed vous voulez passer au fragment D à chaque fois. Remplacez simplement la méthode onBackPressed() dans l'activité principale A et lorsque vous passez à un fragment, puis passez un TAG ou nom de ce fragment par lequel vous avez reconnu ce fragment dans l'activité principale A.

Je donne l'exemple de celui-ci par lequel vous pouvez facilement comprendre que ...

if (savedInstanceState == null) {

   getSupportFragmentManager().beginTransaction().add(R.id.container, new C_fragment(),"xyz").commit();

}

ou si vous vous déplacez du fragment B au fragment C..et au dos de la presse, vous voulez voir le fragment D ... comme ci-dessous

btn.setOnClickListener(new View.OnClickListener() {

    @Override
    public void onClick(View view) {

        getActivity().getSupportFragmentManager().beginTransaction().add(R.id.container, new C_frament(), "xyz").commit();
        ((ActionBarActivity) getActivity()).getSupportActionBar().setTitle("Fragment C");
    }
});

Maintenant, vous devez simplement remplacer la méthode onBackPressed () dans l'activité principale .... comme ci-dessous ..

@Override
public void onBackPressed() {
    FragmentManager fragmentManager =getSupportFragmentManager();
    if (((C_fragment) getSupportFragmentManager().findFragmentByTag("xyz")) != null && ((C_fragment) getSupportFragmentManager().findFragmentByTag("xyz")).isVisible()) {
        Fragment fragment = new D_Fragment();
        fragmentManager.beginTransaction().replace(R.id.container, fragment).commit();
        getSupportActionBar().setTitle("D fragment ");
    } else {
        super.onBackPressed();
    }
}

J'ai utilisé une autre approche comme suit:

  • Un Otto Event Bus pour communiquer entre l'activité et ses fragments
  • Une pile dans l’activité contenant des actions personnalisées arrière encapsulées dans un Runnable défini par le fragment appelant.
  • Lorsque vous appelez onBackPressed dans l'activité de contrôle, la dernière action personnalisée en retour apparaît et exécute sa Runnable. S'il n'y a rien sur la pile, la valeur par défaut super.onBackPressed() est appelée

L'approche complète avec exemple de code est incluse ici comme réponse à cette autre SO question .

1
aoemerson
public class MyActivity extends Activity {

    protected OnBackPressedListener onBackPressedListener;

    public interface OnBackPressedListener {
        void doBack();
    }

    public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
        this.onBackPressedListener = onBackPressedListener;
    }

    @Override
    public void onBackPressed() {
        if (onBackPressedListener != null)
            onBackPressedListener.doBack();
        else
            super.onBackPressed();
    } 

    @Override
    protected void onDestroy() {
        onBackPressedListener = null;
        super.onDestroy();
    }
}

dans votre fragment, ajoutez ce qui suit, n'oubliez pas d'implémenter l'interface de mainactivity.

public class MyFragment extends Framgent implements MyActivity.OnBackPressedListener {
    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
         ((MyActivity) getActivity()).setOnBackPressedListener(this);
    }

@Override
public void doBack() {
    //BackPressed in activity will call this;
}

}
1
joelvarma

sur mainActivity

protected DrawerHomeActivity.OnBackPressedListener onBackPressedListener;

public interface OnBackPressedListener {
    void doBack();
}

public void setOnBackPressedListener(DrawerHomeActivity.OnBackPressedListener onBackPressedListener) {
    this.onBackPressedListener = onBackPressedListener;
}

@Override
public void onBackPressed() {
    if (onBackPressedListener != null) {
        onBackPressedListener.doBack();
    } else { 
        super.onBackPressed();
    }
}

sur le fragment implémenter l'activité de base/fragment comme

implements DrawerHomeActivity.OnBackPressedListener

DraweHomeActivity est mon activité de base écrire

((DrawerHomeActivity) getActivity()).setOnBackPressedListener(this);

et créer la méthode doBack

@Override
public void doBack() {
    //call base fragment 
}
0
Mahesh Pandit

Vous devez remplacer le onBackPressed () avec l'écouteur de fragment. Voici comment:

https://stackoverflow.com/a/51228447/7451779

0
Haider Malik

J'ai eu le même problème et j'ai créé un nouvel auditeur et utilisé dans mes fragments.

1 - Votre activité doit avoir une interface d’écoute et une liste des auditeurs.

2 - Vous devez implémenter des méthodes pour ajouter et supprimer les écouteurs

3 - Vous devez remplacer la méthode onBackPressed pour vérifier que les écouteurs utilisent ou non la presse arrière

public class MainActivity ... {

    /**
     * Back press listener list. Used for notifying fragments when onBackPressed called
     */
    private Stack<BackPressListener> backPressListeners = new Stack<BackPressListener>();


    ...

    /**
     * Adding new listener to back press listener stack
     * @param backPressListener
     */
    public void addBackPressListener(BackPressListener backPressListener) {
        backPressListeners.add(backPressListener);
    }

    /**
     * Removing the listener from back press listener stack
     * @param backPressListener
     */
    public void removeBackPressListener(BackPressListener backPressListener) {
        backPressListeners.remove(backPressListener);
    }


    // Overriding onBackPressed to check that is there any listener using this back press
    @Override
    public void onBackPressed() {

        // checks if is there any back press listeners use this press
        for(BackPressListener backPressListener : backPressListeners) {
            if(backPressListener.onBackPressed()) return;
        }

        // if not returns in the loop, calls super onBackPressed
        super.onBackPressed();
    }

}

4 - Votre fragment doit implémenter l'interface pour la presse arrière

5 - Vous devez ajouter le fragment en tant qu'auditeur pour la presse arrière

6 - Vous devez retourner true à partir de onBackPressed si le fragment utilise cette dernière

7 - IMPORTANT - Vous devez supprimer le fragment de la liste onDestroy

public class MyFragment extends Fragment implements MainActivity.BackPressListener {


    ...

    @Override
    public void onAttach(Activity activity) {
        super.onCreate(savedInstanceState);

        // adding the fragment to listener list
        ((MainActivity) activity).addBackPressListener(this);
    }

    ...

    @Override
    public void onDestroy() {
        super.onDestroy();

        // removing the fragment from the listener list
        ((MainActivity) getActivity()).removeBackPressListener(this);
    }

    ...

    @Override
    public boolean onBackPressed() {

        // you should check that if this fragment is the currently used fragment or not
        // if this fragment is not used at the moment you should return false
        if(!isThisFragmentVisibleAtTheMoment) return false;

        if (isThisFragmentUsingBackPress) {
            // do what you need to do
            return true;
        }
        return false;
    }
}

Il existe une pile utilisée à la place de ArrayList pour pouvoir démarrer à partir du dernier fragment. Il peut également y avoir un problème lors de l’ajout de fragments à la pile arrière. Donc, vous devez vérifier que le fragment est visible ou non tout en utilisant la presse arrière. Sinon, l'un des fragments utilisera l'événement et le dernier fragment ne sera pas fermé lors de la dernière publication.

J'espère que cela résout le problème pour tout le monde.

0
eluleci

Manière facile de gérer onBackPressed () dans les fragments

Étape 1: Créez un booléen statique en activité.

public static Fragment_one;

Étape 2: Sur MainActivity (Activité contenant un fragment) dans la méthode On Create, déclarez

Fragment_one=true;

Étape 3: Remplacer onBackPressed () dans MainActivity

@Override
public void onBackPressed() {

    if(Fragment_one) {
     //Back key pressed on fragment one

    }else {
      //Back key pressed on fragment two
    }
}

Étape 4: Sur la méthode fragment_one onCreateView declare

MainActivity.Fragment_one=true;

Étape 5 Sur la méthode fragment_two onCreateView declare

MainActivity.Fragment_one=false;

Note: Cette méthode ne peut être appliquée qu'à DEUX fragments.

0
Elaiya

Fragment: Créer un fragment de base plaçant une méthode:

 public boolean onBackPressed();

Activité:

@Override
public void onBackPressed() {
    List<Fragment> fragments = getSupportFragmentManager().getFragments();
    if (fragments != null) {
        for (Fragment fragment : fragments) {
            if (!fragment.isVisible()) continue;

            if (fragment instanceof BaseFragment && ((BaseFragment) fragment).onBackPressed()) {
                return;
            }
        }
    }

    super.onBackPressed();
}

Votre activité passera sur les fragments attachés et visibles et appellera onBackPressed () sur chacun d'eux et abandonnera si l'un d'eux renvoie 'true' (ce qui signifie qu'elle a été traitée, donc pas d'autres actions). .

0
Alécio Carvalho
   @Override
   public boolean onKeyDown(int keyCode, KeyEvent event)
    {
       if ((keyCode == KeyEvent.KEYCODE_BACK))
  {
           finish();
    }
       return super.onKeyDown(keyCode, event);
    }

Il suffit de commenter n'importe quelle méthode associée à une touche vers le bas maintenant addToBackStack fonctionnera. Merci

0
Tasnuva oshin