I'm trying to update my app to use BottomNavigationView
. The first tab contains a HostFragment
with a loading spinner that performs a network request to determine which fragment, either HomeFragment
or LockedFragment
, should be shown in that tab.
MainActivity
handles the initial setup of the BottomNavigationView
:
class MainActivity : AppCompatActivity() {
private lateinit var navController: NavController
private lateinit var appBarConfiguration: AppBarConfiguration
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val navHostFragment = supportFragmentManager.findFragmentById(
R.id.nav_host_container
) as NavHostFragment
navController = navHostFragment.navController
val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottom_nav)
bottomNavigationView.setupWithNavController(navController)
appBarConfiguration = AppBarConfiguration(
setOf(R.id.mainFragment)
)
setupActionBarWithNavController(navController, appBarConfiguration)
}
My main nav graph looks like this:
<?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/nav_graph"
app:startDestination="@ id/home">
<include app:graph="@navigation/home"/>
<include app:graph="@navigation/list"/>
<include app:graph="@navigation/form"/>
</navigation>
with the home graph looking like:
<?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/home"
app:startDestination="@ id/hostFragment">
<fragment
android:id="@ id/hostFragment"
android:name="com.example.android.bottomnav.homescreen.HostFragment"
android:label="Host">
<action
android:id="@ id/action_hostFragment_to_homeFragment"
app:destination="@id/homeFragment" />
<action
android:id="@ id/action_hostFragment_to_lockedFragment"
app:destination="@id/lockedFragment" />
</fragment>
<fragment
android:id="@ id/homeFragment"
android:name="com.example.android.bottomnav.homescreen.HomeFragment"
android:label="Home" />
<fragment
android:id="@ id/lockedFragment"
android:name="com.example.android.bottomnav.homescreen.LockedFragment"
android:label="Locked"/>
</navigation>
HostFragment
get's shown fine and loads it's data:
class HostFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_host, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
determineFragmentToShow()
}
private fun determineFragmentToShow() {
lifecycleScope.launchWhenStarted {
// mock network call to determine tab
delay(1500)
// show HomeFragment for the sake of the example, but note that
// this would be dependent on the network call's result above
findNavController().navigate(R.id.action_hostFragment_to_homeFragment)
}
}
}
which successfully navigates us to HomeFragment
.
Now the problem is that whenever I press the back button from HomeFragment
it goes back to HostFragment
instead of closing the app.You can see the behavior in this video here.
I tried to set the popUpTo
and popUpInclusive
tags inside of home.xml
like this:
<fragment
android:id="@ id/hostFragment"
android:name="com.example.android.bottomnav.homescreen.HostFragment"
android:label="Host">
<action
android:id="@ id/action_hostFragment_to_homeFragment"
app:destination="@id/homeFragment"
app:popUpTo="@id/home"
app:popUpToInclusive="true"/>
<action
android:id="@ id/action_hostFragment_to_lockedFragment"
app:destination="@id/lockedFragment"
app:popUpTo="@id/home"
app:popUpToInclusive="true"/>
</fragment>
That got the app to close when pressing back from HomeFragment
, but now each time I switch to a new tab, it creates a new instance of the fragment and adds it to the backstack. Pressing the back button then will traverse them all backwards. You can see that behavior in this video here.
So how can I update the start destination of a nested navigation graph?
I'm using the latest 2.4.0-alpha10
of navigation component so that I can get native support for multiple backstacks. Any help is greatly appreciated!
CodePudding user response:
I was able to utilize the answer here to get a solution working for me.
Inside of determineFragmentToShow()
in HostFragment
, I just replaced findNavController().navigate(R.id.action_hostFragment_to_homeFragment)
with
val navController = findNavController()
val graph = navController.graph
val walletGraph = graph.findNode(R.id.home) as NavGraph
walletGraph.setStartDestination(R.id.homeFragment)
navController.navigate(R.id.action_hostFragment_to_homeFragment)
I still needed to include the popUpTo
and popUpInclusive
tags here
<fragment
android:id="@ id/hostFragment"
android:name="com.example.android.bottomnav.homescreen.HostFragment"
android:label="Host">
<action
android:id="@ id/action_hostFragment_to_homeFragment"
app:destination="@id/homeFragment"
app:popUpTo="@id/home"
app:popUpToInclusive="true"/>
<action
android:id="@ id/action_hostFragment_to_lockedFragment"
app:destination="@id/lockedFragment"
app:popUpTo="@id/home"
app:popUpToInclusive="true"/>
</fragment>
but this got me the back behavior I was looking for!