architecture-components-samples
architecture-components-samples copied to clipboard
BottomNavigationView. Navigation to destination with deeplink cause to add destination fragment also in first tab
Let's say we have a bottom navigation view with 4 tab, we fave a deeplink for fragment in 4 tab, so when navigate with this deeplink, the 4 tab are selected - it's ok, but when after this manually select firts tab the fragment from 4 tab are added also in first tab.
Problem solved my self with this solution i added an custom extenstion for bottom nav view
fun BottomNavigationView.setupWithNavController(navController: NavController?) {
navController?.let {
this.setupWithNavController(it)
}
this.setOnItemSelectedListener { menuItem ->
val builder = NavOptions.Builder().setLaunchSingleTop(true).setRestoreState(false)
val graph = navController?.currentDestination?.parent
val destination = graph?.findNode(menuItem.itemId)
if (menuItem.order and Menu.CATEGORY_SECONDARY == 0) {
navController?.graph?.findStartDestination()?.id?.let {
builder.setPopUpTo(
it,
inclusive = false,
saveState = true
)
}
}
val options = builder.build()
destination?.id?.let { id -> navController.navigate(id, null, options) }
return@setOnItemSelectedListener true
}
}
problem was in setRestoreState(true)
Please open a ticket here, otherwise they will not fix it, Google Issue Tracker
Hello,
I used navigation components version 2.4.0-alpha04 and I have same issue, my solution is inspired by @AlexMobileStyles, the main problem is with setPopUpTomethod with saveState = true, btw is issue already reported on Google Issue Tracker?
fun BottomNavigationView.setupWithNavControllerFixed(navController: NavController?) {
navController?.let {
this.setupWithNavController(it)
}
NavigationUI
/**
* Fixed by
* NavOptions setRestoreState(false) with setPopUpTo(saveState = true)
* or
* NavOptions setRestoreState(true) with setPopUpTo(saveState = false)
*
* @see [NavigationUI.onNavDestinationSelected]
*/
this.setOnItemSelectedListener {item->
val builder = NavOptions.Builder().setLaunchSingleTop(true).setRestoreState(true)
if (
navController!!.currentDestination!!.parent!!.findNode(item.itemId)
is ActivityNavigator.Destination
) {
builder.setEnterAnim(R.anim.nav_default_enter_anim)
.setExitAnim(R.anim.nav_default_exit_anim)
.setPopEnterAnim(R.anim.nav_default_pop_enter_anim)
.setPopExitAnim(R.anim.nav_default_pop_exit_anim)
} else {
builder.setEnterAnim(R.animator.nav_default_enter_anim)
.setExitAnim(R.animator.nav_default_exit_anim)
.setPopEnterAnim(R.animator.nav_default_pop_enter_anim)
.setPopExitAnim(R.animator.nav_default_pop_exit_anim)
}
if (item.order and Menu.CATEGORY_SECONDARY == 0) {
builder.setPopUpTo(
navController.graph.findStartDestination().id,
inclusive = false,
saveState = false
)
}
val options = builder.build()
return@setOnItemSelectedListener try {
// TODO provide proper API instead of using Exceptions as Control-Flow.
navController.navigate(item.itemId, null, options)
true
} catch (e: IllegalArgumentException) {
false
}
}
}
But this solution breaks multiple stack saved states and whenever we select any bottom nav item, start destination opens instead of last fragment that was there (state is not saved) Any other solution? @KamikX @AlexMobileStyles
I think the situation is significantly worse: the Multiple back stacks is completely broken.
example 1: if I am in a second level of the first tab and I deeplink on tab 2, the first tab stops responding
example 2: if I am in a second level of the first tab, I navigate with a deeplink on tab 2, then click on tab 3 and then click on tab 1, tab 2 is displayed
and much more, all just using AdvancedNavigationSample and navigation component 2.4.0
deeplink created using this code inside About fragment class
view.findViewById<Button>(R.id.deepLink).setOnClickListener {
findNavController().navigate("http://www.example.com/user/Person 2".toUri())
}
Look's like i've found solution
I have two fragments (FragmentA and FragmentB) inside BottomNavigationView
I use this code for navigating to FragmentB inside FragmentA
val navOptions: NavOptions = navBuilder
.setPopUpTo(
R.id.fragmentA,
inclusive = false,
saveState = true
).build()
findNavController().navigate("deeplink://to_fragment_b".toUri(), navOptions)
Backstack working, state saving I used version 2.4.2
Oh no sorry it isn't working correct(( After changing item, back stack isn't saving((
The issue is in the google issue tracker https://issuetracker.google.com/issues/213131384
@Lime94 try using setRestoreState in your navOptions too
navOptionsBuilder.setRestoreState(true)
navController?.graph?.findStartDestination()?.id?.let {
navOptionsBuilder.setPopUpTo(
it,
popUpToInclusive,
saveState = true
)
}
NVM - this still wont fix the backstack if you navigate using deeplinks from a non top-level destination
The solution is here: https://stackoverflow.com/a/78075344/16041661