I am working on Android and I want to reset the navigate back to a intro fragment from anywhere in my application from a drawer menu item.
I saw the popupto option from an action in a fragment but I don't know how to use it in the menu item or even if it possible. May be this is not the right approach, I just want to be able to reset the stack and go back to a defined fragment from a click on a item menu.
Thx
Regards.
Use this code snippet when menuItem Clicked
navController.popBackStack(navController.graph.startDestination,false)
for any case use this code snippet for pop up to some fragment
val navOptions = NavOptions.Builder().setPopUpTo(R.id.popUpToFragmentId, true).build()
navController.navigate(R.id.destinationFragmentId, navOptions)
So after re reading the url from where I get the solution, it should clear the stack so my answer is this :
fun navigateFirstTabWithClearStack() {
val navController = findNavController(R.id.nav_host_main)
val navHostFragment: NavHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_main) as NavHostFragment
val inflater = navHostFragment.navController.navInflater
val graph = inflater.inflate(R.navigation.nav_graph_main)
graph.startDestination = R.id.nav_graph_tab1
navController.graph = graph
}
Solution from : https://github.com/android/architecture-components-samples/issues/767
just make sure that the id of the menu item matches the id of the chosen destination and then call:
// Tie all menu items in the drawer to their respective destinations
NavigationUI.setupWithNavController(navView, navController)
or
// tie only the given item to a destination
val menuItem = navView.menu.findItem(R.id.menu_item)
NavigationUI.onNavDestinationSelected(menuItem, navController)
clearing the backStack before navigating to your chosen destination is the default behavior unless the menu item has menuCategory="secondary".
Related
I have a bottom navigation bar which is connected with navHost and is configured using the following code:
Val navHostFragment =supportFragmentManager.findFragmentById(R.id.fragment) as NavHostFragment
val navController = navHostFragment.navController
val bottomNavBar = findViewById<BottomNavigationView>(R.id.bottomBar)
setupWithNavController(bottomNavBar, navController)
I have 4 fragments now when I switch to 2nd fragment(by clicking on 2nd icon in the bottom navigation bar) and then I navigate to another fragment which is linked to the 2nd fragment. When I click on the back button I switch to 2nd fragment.
All good till far.
The problem is: I want to go back to 2nd fragment from the opened fragment when I reselect the same icon in the bottom navigation bar
I solved my issue with the help of this thread. If someone is facing the same issue, check this out:
Android clear backstack after reselecting Bottom Navigation tab
I have integrated a better solution which lets you have animations too when switching from one fragment to another.
val id = navController.currentDestination?.id
when (id) {
R.id.detailedTransactionAnalysis -> {
navController.navigate(R.id.action_detailedTransactionAnalysis_to_MainScreen)
}
R.id.detailedCategoryTransactionsFragment -> {
navController.navigate(R.id.action_detailedCategoryTransactionsFragment_to_MainScreen)
}
R.id.addTransaction -> {
navController.navigate(R.id.action_addTransaction_to_Stats)
}
}
navController.popBackStack(reselectedDestinationId, inclusive = false)
It works totally fine.
I have a NavigationView (Drawer) with 5 menus each pointing to 5 different fragments. Say Fragment A,B,C,D,E.
Now I want to navigate to fragment C on clicking a notification (Pending Intent)
This is my deepLink
return NavDeepLinkBuilder(this)
.setComponentName(MainActivity::class.java)
.setGraph(R.navigation.mobile_navigation)
.setDestination(R.id.nav_fragment_c)
.setArguments(args)
.createPendingIntent()
It navigates to the fragment but suppose the user is currently on fragment A, the deep link adds the fragment on top of fragment A and won't let the user navigate back to fragment A even on clicking the drawer menu A (behaves like it's disabled). However, on clicking the back button it takes the user back to fragment A and everything works fine again (I guess it pops the fragment).
Am I doing something wrong here? How do I tell the navController to navigate to the desired fragment without adding it on top of whichever fragment the user is currently on.
Also noticed the same behavior when I do navController.navigate(destinationId)
Here is my navContoller
val navController = findNavController(R.id.nav_host_fragment_content_main)
binding.navView?.let {
appBarConfiguration = AppBarConfiguration(
setOf(
R.id.nav_fragment_a,
R.id.nav_fragment_b,
R.id.nav_fragment_c,
R.id.nav_fragment_d,
R.id.nav_fragment_e,
),
binding.drawerLayout
)
setupActionBarWithNavController(navController, appBarConfiguration)
it.setupWithNavController(navController)
}
Good day. So I've been working around with NavComponent of Jetpack for Android
I've thought that management of BackStack of fragments had to be implemented there already, well in fact it is there but I have faced an issue.
Here is my structure:
I have and entry Activity
I have a NavHost in the activity
I have Bottom Navigation bar in the Activity
For each Bottom Item I am using separate Fragments to navigate through.
Here is the code for the navigation.
bottomNavigationView.setOnNavigationItemSelectedListener {
when (it.itemId) {
R.id.navigation_home -> {
navController.apply {
navigate(R.id.navigation_home)
}
true
}
R.id.navigation_dashboard -> {
navController.apply {
navigate(R.id.dashboardFragment)
}
true
}
R.id.navigation_notifications -> {
true
}
else -> {
false
}
}
}
Never mind the last item.
So the issue is next.
If I try to switch between home and dashboard multiple times, when I press back then the stack surely will start popping all the items included there. So if I move like 6 times it will take me 12 attempts to actually exit the app.
Currently I couldn't find any source where for example the navigate() method will accept some sort of argument to cash my fragments instead of recreating it each time and adding to the BackStack.
So what kind of approach would you suggest?
If I to manage the BackStack manually on each back button pressed, what's the purpose of NavController at all? Just for creating and FORWARD navigation?
I think I'm missing some source in Android's official docs.
Thank you beforehand.
P.S.
using navController.popBackStack() before calling navigate() surely isn't the correct choice.
According to the documentation here :
NavigationUI can also handle bottom navigation. When a user selects a menu item, the NavController calls onNavDestinationSelected() and automatically updates the selected item in the bottom navigation bar.
to do so you have to give your bottom navigation items an ids as same as the corresponding destination in your navigation graph , and then tie you bottom view to the controller like this :
NavHostFragment navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment);
NavController navController = navHostFragment.getNavController();
BottomNavigationView bottomNav = findViewById(R.id.bottom_nav);
NavigationUI.setupWithNavController(bottomNav, navController);
Note : from my personal experience , when the startDestination in the graph , that start by default is not currently in back stack (In my case it was the landing page which i pop it out when going to home fragment) then the app act with weird behavior like this . so make sure the start destination is existed in your back stack on should work fine .
I am working on the project NavigationAdvancedSample of the
architecture-components-samples repository. This project shows a workaround to support multiple back stacks for each tab of a BottomNavigationView.
In this configuration, you define a navigation graph for each of your tabs and let the class extension NavigationExtensions handle the different back stacks for you. Everything works fine, but I can't find a way to select the starting tab of the BottomNavigationView. I have tried to tweak the NavigationExtensions but without success.
By default, the selected tab on the application startup is the first of the bottom navigation view. How can I change this behavior in order to show the second or third tab for example?
Changing order of items in the navGraphIds and selecting item in bottomNavigationView helped me.
private fun setupBottomNavigationBar() {
val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottom_nav)
val navGraphIds = listOf(R.navigation.list, R.navigation.home, R.navigation.form)
bottomNavigationView.selectedItemId = R.id.list
// Setup the bottom navigation view with a list of navigation graphs
val controller = bottomNavigationView.setupWithNavController(
navGraphIds = navGraphIds,
fragmentManager = supportFragmentManager,
containerId = R.id.nav_host_container,
intent = intent
)
// Whenever the selected controller changes, setup the action bar.
controller.observe(this, Observer { navController ->
setupActionBarWithNavController(navController)
})
currentNavController = controller
}
As a result I have R.id.list item as first.
I am using Navigation Component with Navigation Drawer.
I have added Fragments for each Navigation item in the menu.
Add NavHostFragment where this Fragment will be swapped
Then added Fragments as Destinations
I want master Detail Navigation i.e.
start destination -> fragment 2
back button -> start destination
start destination -> fragment 2 -> fragment 3 -> fragment 4
back button -> start destination
My question is whether I should add any connections to this graph?
I also need to have one menu item which is just logout function call not fragment swapping, so I could not configure it with default setup
val navController = findNavController(R.id.main_nav_host_fragment)
nav_view.setupWithNavController(navController)
But rather have to use
nav_view.setNavigationItemSelectedListener(this)
override fun onNavigationItemSelected(item: MenuItem): Boolean {
// Handle navigation view item clicks here.
when (item.itemId) {
R.id.navSignOut -> {
loginViewModel.logout()
}
else -> {
val navController = findNavController(R.id.main_nav_host_fragment)
navController.navigate(item.itemId)
}
}
drawer_layout.closeDrawer(GravityCompat.END)
return true
}
I also need to show Login Activity above (modally) the Main App Activity with Navigation Drawer. Can I use Navigation Graph for it and how?
Login Activity should: on back button -> close app, if logged out -> start above main activity, if logged in go to main activity
So I have to questions:
1. Should I use any actions?
2. Should I use custom navigation for drawer or setupWithNavController()?
3. What about modal login activity navigation?
The part I undrestood from your question is how to navigate to logout.
Usually when the user clicks on logout you want to log them out and navigate to a startup screen.
So you need to add your startup activity to nav_graph.
Michael, navigation architecture it is not that easy to understand at the beginning, what you want to is not the exception. But as this navigation is new, I just suggest you to follow the code lab.
https://codelabs.developers.google.com/codelabs/android-navigation/#0
I see for instance your line to close the drawer. The code lab has instructions on how to setup the nav drawer with navigation and the UI
I hope it helps you.