103 votes

Gestion du bouton de retour dans le composant de navigation Android

Je voudrais savoir comment gérer correctement le système de bouton de retour action en utilisant la manette de Navigation. Dans mon application j'ai deux fragments (par ex. fragment1 et fragment2) et j'ai une action en fragment1 à destination de fragment2. Tout fonctionne bien sauf une chose: quand l'utilisateur appuie sur le système de bouton retour dans fragment2 je veux afficher une boîte de dialogue (à l'aide de DialogFragment par exemple) pour confirmer la sortie. Quelle est la meilleure façon de mettre en œuvre ce comportement? Si j'utilise app:defaultNavHost="true" de mon hôte fragment puis il revient automatiquement en ignorant mes règles. Et, en outre, quel est ce composant?

enter image description here

Dois-je utiliser "pop" peut-être?

185voto

Jurij Pitulja Points 840

Nouvelle mise à Jour - 25 avril 2019

Nouvelle version androidx.l'activité du ver. 1.0.0-alpha07 apporte quelques modifications

Plus d'explications dans android guide officiel: personnaliser le dos de navigation

Exemple:

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()
    }
    ...
}

Vieux Mises À Jour

UPD: 3 avril 2019

Maintenant simplifié. Plus d'infos ici

Exemple:

requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(), this);

@Override
public boolean handleOnBackPressed() {
    //Do your job here
    //use next line if you just need navigate up
    //NavHostFragment.findNavController(this).navigateUp(); 
    //Log.e(getClass().getSimpleName(), "handleOnBackPressed");
    return true;
    }

Obsolète (depuis la Version 1.0.0-alpha06 3 avril 2019) :

Depuis cela, il peut être implémenté à l'aide de JetPack mise en oeuvre OnBackPressedCallback dans votre fragment et l'ajouter à l'activité: getActivity().addOnBackPressedCallback(getViewLifecycleOwner(),this);

Votre fragment devrait ressembler à ceci:

public MyFragment extends Fragment implements OnBackPressedCallback {

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

        getActivity().addOnBackPressedCallback(getViewLifecycleOwner(),this);
}

    @Override
    public boolean handleOnBackPressed() {
        //Do your job here
        //use next line if you just need navigate up
        //NavHostFragment.findNavController(this).navigateUp(); 
        //Log.e(getClass().getSimpleName(), "handleOnBackPressed");
        return true;
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        getActivity().removeOnBackPressedCallback(this);
    }
}

UPD: Votre activité doit s'étend AppCompatActivityou FragmentActivity et dans Gradle fichier:

 implementation 'androidx.appcompat:appcompat:{lastVersion}'

24voto

Kiryl Tkach Points 1066

J'ai donc créé une interface

 public interface OnBackPressedListener {
    void onBackPressed();
}
 

Et implémenté par tous les fragments qui doivent gérer le bouton de retour. Dans l'activité principale, j'ai remplacé la méthode onBackPressed() :

 @Override
public void onBackPressed() {
    final Fragment currentFragment = mNavHostFragment.getChildFragmentManager().getFragments().get(0);
    final NavController controller = Navigation.findNavController(this, R.id.nav_host_fragment);
    if (currentFragment instanceof OnBackPressedListener)
        ((OnBackPressedListener) currentFragment).onBackPressed();
    else if (!controller.popBackStack())
        finish();

}
 

Donc, si le fragment supérieur de mon hôte de navigation implémente l'interface OnBackPressedListener , j'appelle sa méthode onBackPressed() , ailleurs je fais simplement apparaître la pile et ferme l'application si la pile arrière est vide.

11voto

Alex Points 2578

Voici une solution qui devrait faire ce que vous voulez, mais je pense que c'est une mauvaise solution, car elle va à l'encontre de l'idée du composant de navigation Android (laisser l'androïde gérer la navigation).

Remplacez "onBackPressed" dans votre activité

 override fun onBackPressed() {
    when(NavHostFragment.findNavController(nav_host_fragment).currentDestination.id) {
        R.id.fragment2-> {
            val dialog=AlertDialog.Builder(this).setMessage("Hello").setPositiveButton("Ok", DialogInterface.OnClickListener { dialogInterface, i ->
                finish()
            }).show()
        }
        else -> {
            super.onBackPressed()
        }
    }
} 
 

9voto

Sai Points 136

J'ai écrit dans l'activité principale comme ça,

 override fun onSupportNavigateUp(): Boolean {
        return findNavController(R.id.my_nav_host_fragment).navigateUp(appBarConfiguration)
    }   
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X