Android JetPack navigation with multiple stack

前端 未结 1 1295
情书的邮戳
情书的邮戳 2020-12-24 09:42

I\'m using Jetpack Navigation version 1.0.0-alpha04 with bottom navigation. It works but the navigation doesn\'t happen correctly. For example, if I have tab A

相关标签:
1条回答
  • 2020-12-24 10:05

    EDIT 2: Though still no first class support (as of writing this), Google has now updated their samples with an example of how they think this should be solved for now: https://github.com/googlesamples/android-architecture-components/tree/master/NavigationAdvancedSample


    The major reason is you only use one NavHostFragment to hold the whole back stack of the app.

    The solution is that each tab should hold its own back stack.

    • In your main layout, wrap each tab fragment with a FrameLayout.
    • Each tab fragment is a NavHostFragment and contains its own navigation graph in order to make each tab fragment having its own back stack.
    • Add a BottomNavigationView.OnNavigationItemSelectedListener to BottomNavigtionView to handle the visibility of each FrameLayout.

    This also takes care of your "...I don't like to keep all this fragment in memory...", because a Navigation with NavHostFragment by default uses fragmentTransaction.replace(), i.e. you will always only have as many fragments as you have NavHostFragments. The rest is just in the back stack of your navigation graph.

    Edit: Google is working on a native implementation https://issuetracker.google.com/issues/80029773#comment25


    More in detail

    Let's say you have a BottomNavigationView with 2 menu choices, Dogs and Cats.

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

    Then you need 2 navigation graphs, say dog_navigation_graph.xml and cat_navigation_graph.xml.

    The dog_navigation_graph might look like

    <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>
    

    and the corresponding for cat_navigation_graph.

    In your activity_main.xml, add 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>
    

    and underneath add the corresponding for your cat NavHostFragment. On your cat frame layout, set android:visibility="invisible"

    Now, in your MainActivity's onCreateView you can

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

    All that showHostView() is doing is toggling the visibility of your FrameLayouts that are wrapping the NavHostFragments. So make sure to save them in some way, e.g. in onCreateView

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

    Now it's easy to toggle which hostViews should be visible and invisible.

    0 讨论(0)
提交回复
热议问题