web-dev-qa-db-fra.com

Android Navigation JetPack avec plusieurs piles

J'utilise Jetpack Navigation version 1.0.0-alpha04 avec navigation en bas. Cela fonctionne mais la navigation ne se fait pas correctement. Par exemple, si j'ai l'onglet A et l'onglet B et de l'onglet AI aller à la page C et à partir de là, je vais à l'onglet B et reviens à l'onglet A à nouveau, je verrai un fragment de racine dans l'onglet A et pas la page C qui ne pas ce que j'attends.

Je cherche une solution pour avoir une pile différente pour chaque onglet, donc l'état de chaque onglet est réservé quand j'y reviens, aussi je n'aime pas garder tout ce fragment en mémoire car il a un mauvais effet sur les performances, Avant la navigation Jetpack, j'ai utilisé cette bibliothèque https://github.com/ncapdevi/FragNav , Cela fait exactement quoi, maintenant je cherche la même chose avec la navigation Jetpack.

8
Alireza A. Ahmadi

EDIT 2: Bien qu'il n'y ait toujours pas de support de première classe (au moment d'écrire ceci), Google a maintenant mis à jour ses échantillons avec un exemple de la façon dont ils pensent que cela devrait être résolu pour l'instant: https://github.com/googlesamples/Android-architecture-components/tree/master/NavigationAdvancedSample


La raison principale est que vous n'utilisez qu'un NavHostFragment pour contenir toute la pile arrière de l'application.

La solution est que chaque onglet doit contenir sa propre pile arrière.

  • Dans votre mise en page principale, enveloppez chaque fragment d'onglet avec un FrameLayout.
  • Chaque fragment d'onglet est un NavHostFragment et contient son propre graphique de navigation afin que chaque fragment d'onglet ait sa propre pile arrière.
  • Ajoutez un BottomNavigationView.OnNavigationItemSelectedListener À BottomNavigtionView pour gérer la visibilité de chaque FrameLayout.

Cela prend également en charge votre "... je n'aime pas garder tout ce fragment en mémoire ...", car une navigation avec NavHostFragment par défaut utilise fragmentTransaction.replace(), c'est-à-dire vous aura toujours autant de fragments que vous avez NavHostFragments. Le reste est juste dans la pile arrière de votre graphique de navigation.

Modifier: Google travaille sur une implémentation native https://issuetracker.google.com/issues/80029773#comment25


Plus en détail

Disons que vous avez un BottomNavigationView avec 2 choix de menu, Dogs et Cats.

<menu xmlns:Android="http://schemas.Android.com/apk/res/Android">
    <item Android:id="@+id/dogMenu"
        .../>

    <item Android:id="@+id/catMenu"
        .../>
</menu>

Ensuite, vous avez besoin de 2 graphiques de navigation, dites dog_navigation_graph.xml Et cat_navigation_graph.xml.

Le dog_navigation_graph Pourrait ressembler à

<navigation
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:app="http://schemas.Android.com/apk/res-auto"
    Android:id="@+id/dog_navigation_graph"
    app:startDestination="@id/dogMenu">
</navigation>

et le correspondant pour cat_navigation_graph.

Dans votre activity_main.xml, Ajoutez 2 NavHostFragments

<FrameLayout
    Android:id="@+id/frame_dog"
    ...>

    <fragment
        Android:id="@+id/dog_navigation_Host_fragment"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:name="androidx.navigation.fragment.NavHostFragment"
        app:navGraph="@navigation/dog_navigation_graph"
        app:defaultNavHost="true"/>
</FrameLayout>

et en dessous ajoutez le correspondant pour votre chat NavHostFragment. Sur la disposition de votre cadre de chat, définissez Android:visibility="invisible"

Maintenant, dans votre MainActivityonCreateView vous pouvez

bottom_navigation_view.setOnNavigationItemSelectedListener { item ->
    when (item.itemId) {
        R.id.dogMenu -> showHostView(Host = 0)
        R.id.catMenu -> showHostView(Host = 1)
    }
    return@setOnNavigationItemSelectedListener true
}

Tout ce que showHostView() fait est de basculer la visibilité de vos FrameLayouts qui enveloppent les NavHostFragments. Assurez-vous donc de les enregistrer d'une manière ou d'une autre, par exemple dans onCreateView

val hostViews = arrayListOf<FrameLayout>()  // Member variable of MainActivity
hostViews.apply {
    add(findViewById(R.id.frame_dog))
    add(findViewById(R.id.frame_cat))
}

Il est maintenant facile de basculer entre hostViews qui devrait être visible et invisible.

11
Algar