web-dev-qa-db-fra.com

Graphique de navigation avec plusieurs destinations de premier niveau

J'implémente une Android (dans Kotlin, mais qui n'est pas pertinente pour le problème) pendant mon temps libre et j'essaie d'utiliser Android jetpack et nouveau) bibliothèques. J'ai une seule activité avec un tiroir de navigation. J'essaie de suivre exemple d'application de tournesol . Il utilise la combinaison suivante dans l'activité principale pour activer la logique derrière le tiroir de navigation:

appBarConfiguration = AppBarConfiguration(navController.graph, drawerLayout)
setSupportActionBar(findViewById(R.id.toolbar))
setupActionBarWithNavController(navController, appBarConfiguration)

Remarque sur ce code : Cela naviguera automatiquement vers les bons fragments lorsque vous cliquez dessus dans le tiroir de navigation et fermera le tiroir et les gardera sélectionnés etc. Tout ce passe-partout code. C'est assez soigné et ça marche aussi. Pour autant que je comprends cela, les ID des éléments de menu du tiroir de navigation doivent correspondre aux ID des fragments dans le graphique de navigation et de cette façon, ils sont connectés.

Le problème que j'ai : Lorsque j'utilise le tiroir de navigation pour accéder à n'importe quel fragment autre que le fragment de départ du graphique de navigation, il affichera un bouton de retour au lieu de l'élément hamburger. Ce n'est pas ce que j'attends, je m'attendrais à ce que ce soit toujours l'élément hamburger puisque le tiroir de navigation sert à naviguer entre les vues à un niveau égal et non imbriqué les uns dans les autres, non? Je m'attends à un bouton de retour si je navigue vers un sous-fragment d'un fragment en cliquant sur les éléments de ce fragment (par exemple, liste -> détail) mais pas si je navigue à l'aide du tiroir de navigation.

Maintenant, j'ai retracé ce problème au générateur AppBarConfiguration qui lit sur le constructeur prenant un navgraph The NavGraph whose start destination should be considered the only top level destination. Je peux résoudre ce problème assez facilement en remplaçant AppBarConfiguration pour renvoyer des destinations de premier niveau différentes de la seule destination de départ du graphique de navigation.

Cependant ma question est, pourquoi ce comportement est-il par défaut? Est-ce un bug? Si je remplace cela, est-ce que je violerai certaines directives de conception de Google? Tous les éléments du tiroir de navigation ne devraient-ils pas être au même niveau que ce à quoi je m'attends? Existe-t-il une solution différente que je souhaite faire?

9
findusl

Vous n'avez pas à remplacer AppBarConfiguration. Depuis la version alpha7 AppBarConfiguration possède un constructeur avec un ensemble d'identifiants pour toutes les destinations de niveau supérieur.

Set<Integer> topLevelDestinations = new HashSet<>();
topLevelDestinations.add(R.id.fragment1);
topLevelDestinations.add(R.id.fragment2);
appBarConfiguration = new AppBarConfiguration.Builder(topLevelDestinations)
                                             .setDrawerLayout(drawerLayout)
                                             .build();
NavigationUI.setupActionBarWithNavController(this, 
                                             this.navController,
                                             this.appBarConfiguration);

Ce n'est pas par défaut car le graphique de navigation n'a qu'un seul fragment de démarrage qui doit toujours être le point d'entrée unique de l'application.

La modification du comportement par défaut avec AppBarConfiguration ne le fait pas se comporter comme auparavant, chaque fragment de niveau supérieur est placé sur la pile arrière, donc le bouton de retour ira à tous les fragments de niveau supérieur. On ne sait pas comment je peux créer des fragments de premier niveau comme premier élément de la pile arrière.

18
Elias DC

J'ai fait un exemple simple pour ce problème. https://github.com/isaul32/Android-sunflower

Créez d'abord un ensemble de destinations de premier niveau

val topLevelDestinations = setOf(R.id.garden_fragment,
        R.id.plant_list_fragment)
appBarConfiguration = AppBarConfiguration.Builder(topLevelDestinations)
        .setDrawerLayout(drawerLayout)
        .build()

puis remplacer la fonction onSupportNavigateUp comme celle-ci

override fun onSupportNavigateUp(): Boolean {
    return NavigationUI.navigateUp(navController, appBarConfiguration)
}
4
iSaul

Pour obtenir un comportement correct de la barre d'outils et du tiroir avec plusieurs destinations de premier niveau, vous pouvez utiliser le code suivant:

val navController = Navigation.findNavController(this, R.id.nav_Host_fragment)
val toolbar = findViewById<Toolbar>(R.id.toolbar)
val drawerLayout = findViewById<DrawerLayout>(R.id.drawer_layout)

/*
Create AppBarConfiguration with set of top level destinations and drawerLayout
Set contains ids of your navigation graph screens
*/
val appBarConfiguration = AppBarConfiguration(
    setOf(R.id.defaultFragment, R.id.firstFragment, R.id.secondFragment), 
    drawer_layout
)

//finally configure toolbar
toolbar.setupWithNavController(navController, appBarConfiguration)

Ce code garantira que l'icône de hamburger est affichée sur toutes vos destinations de premier niveau, et le bouton de retour apparaîtra lorsque vous naviguerez plus profondément.

En savoir plus ici

1
UrosKekovic