0

I have an app similar to Android Studios Navigation Drawer Activity:

My activity uses Android Architecture Navigation Components & a navigation drawer to navigate between different fragments. As the navigation drawer is pretty custom i can't use the usual navigation-view, but use a custom fragment hosting a LinearLayout. Each item in that LinearLayout has an onClickListener which boils down to

navController.navigate(R.id.myCorrespondingFragment)

So far, so everything works fine. The problem begins when navigating back:

Let's imagine i navigate from "Home"-Fragment A -> B -> C and then go back.

Android Studios example behaves correctly: C -> A -> close

My implementation doesn't: it just pops the backstack C -> B -> A -> close

How do i fix that?


Minified Main-Layout:

<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout  android:id="@+id/drawerLayout" >

    <LinearLayout android:orientation="vertical" >

            <androidx.appcompat.widget.Toolbar  android:id="@+id/toolbar" />
        
        <fragment
            android:id="@+id/container"
            android:name="androidx.navigation.fragment.NavHostFragment"
            app:defaultNavHost="true"
            app:navGraph="@navigation/nav_graph"
            />

    </LinearLayout>

    <fragment
        android:name="com.company.drawer.DrawerFragment"
        android:layout_gravity="start"
        />

</androidx.drawerlayout.widget.DrawerLayout>

Navigation graph:

<?xml version="1.0" encoding="utf-8"?>
<navigation
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/navigation_graph"
    app:startDestination="@id/doorFragment"
    >

    <fragment
        android:id="@+id/doorFragment"
        android:name="com.company.door.DoorFragment"
        android:label="@string/shared_empty"
        />

    <fragment
        android:id="@+id/historyFragment"
        android:name="com.company.history.HistoryFragment"
        android:label="@string/history"
        />

    <fragment
        android:id="@+id/settingsFragment"
        android:name="com.company.settings.SettingsFragment"
        android:label="@string/settings"
        />
</navigation>

Everything navigation related from my Main Activity's onCreate:

setSupportActionBar(toolbar)     
val navController = (supportFragmentManager.findFragmentById(R.id.container) as NavHostFragment).navController
toolbar.setupWithNavController(navController, AppBarConfiguration(
    listOf(R.id.doorFragment, R.id.historyFragment, R.id.settingsFragment)
    , drawerLayout
))
m.reiter
  • 1,796
  • 2
  • 11
  • 31

2 Answers2

0

You can try like this

<fragment
android:id="@+id/fragmentA"
android:name="com.package.FragmentA"
android:label="Fragment A">

<action
    android:id="@+id/action_fragmentA_to_fragmentB"
    app:destination="@id/fragmentB"
    app:popUpTo="@id/fragmentB"
    app:popUpToInclusive="true / false" />
</fragment>
raj kavadia
  • 926
  • 1
  • 10
  • 30
0

You can use global actions, so that you don't have to add an action for every fragment to fragment navigation but only for every fragment destination. This would look like this in XML:

<action android:id="@+id/action_global_doorFragment"
    app:destination="@id/doorFragment"
    app:popUpTo="@id/@id/doorFragment"
    app:restoreState="true"
    app:popUpToSaveState="true" />
<action android:id="@+id/action_global_historyFragment"
    app:destination="@id/historyFragment"
    app:popUpTo="@id/@id/doorFragment"
    app:restoreState="true"
    app:popUpToSaveState="true" />
<action android:id="@+id/action_global_settingsFragment"
    app:destination="@id/historyFragment"
    app:popUpTo="@id/@id/doorFragment"
    app:restoreState="true"
    app:popUpToSaveState="true" />

Note that I always used your start destination for popUpTo and also save the backstack state. You don't necessarily need the latter (restoreState and popUpToSaveState) for your use case but maybe want it later down the road when you have multiple fragments for a single drawer entry. This will get you the same behaviour as the current standard drawer integration.

Here's an easy example on how you can use the global action to go to your settings fragment. (The docs also explain how you can use global actions with the SafeArgs Gradle Plugin which is probably the better method.)

navController.navigate(R.id.action_global_settingsFragment)

If you don't want an extra action for every destination and your drawer menu items have the same id as its destination, you can also do it programmatically like this:

override fun onNavigationItemSelected(item: MenuItem): Boolean {
    navController.navigate(item.itemId, null, navOptions {
        restoreState = true
        popUpTo(navController.graph.findStartDestination().id) {
            saveState = true
        }
    })

    return true
}
Lorion
  • 310
  • 2
  • 10