I am using bottom nav bar. Everything works perfectly but when I open a new fragment and destroy it using back press button my app's going back base fragment but bottom nav bar selected item doesn't change. It stays last clicked position. Let me explain with some pictures
Image 1 +++ Image 2 +++ Image 3
As you can see i'm opening fragment when bottom nav bar's selected item is profile item. Then i'm using back press and going back to main fragment but bottom nav bar's selected item is still profile item.
Host Fragment: The function is inside of onViewcreated (I'm using replacefragment function to set base fragment for first opening)
binding.bottomNavigationView.setOnItemSelectedListener {
when(it.itemId){
R.id.nav_profile -> {replaceFragment(ProfileFragment())
}
R.id.nav_mainpage -> {replaceFragment(MainPageFragment())
}
}
return#setOnItemSelectedListener true
}
replaceFragment(MainPageFragment())
private fun replaceFragment(fragment: Fragment){
val transaction = activity?.supportFragmentManager?.beginTransaction()
transaction?.replace(R.id.frameLayout,fragment)
transaction?.commit()
}
What I tried:I tried this method and it's variants but none of them works
binding.bottomNavigationView.selectedItemId = R.id.nav_mainpage
Try using this:
binding.bottomNavigationView.setSelectedItemId(R.id.nav_mainpage)
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.
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 have such code setup for navigation architecture component:
val navController = findNavController(R.id.main_nav_host_fragment)
nav_view.setupWithNavController(navController)
bottom_navigation.setupWithNavController(navController)
//nav_view.setNavigationItemSelectedListener(this)
navController.addOnNavigatedListener { controller, destination ->
if(destination.id == R.id.loginActivity) {
Toast.makeText(context, "Log Out navigation destination", Toast.LENGTH_LONG).show()
}
}
And I have found here two issues:
Selecting in Navigation Drawer Menu Item that doesn't appear on Bottom Navigation View causes to select first Menu Item in Bottom Navigation View. Which seems to be incorrect (No Item should be selected there)
OnNavigatedListener is not called when selecting Menu Item in Navigation Drawer that has menu item id set to Activity Destination (precisely action to Activity Destination) - so instead of intercepting this action and log out user, I need to pass stupid default arguments to Activity Destination in Nav Graph to log out user in Login Activity Destination. Do you know why OnNavigatedListener is not called for Activity Destinations, and is only called for Fragment Destinations? Why there is not event listener OnBeginNavigationListener to conditionally prevent navigation or add some side effects?
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.
I have an app with a main activity which loads a navigation drawer, and a pair of fragments that load in that activity ...
In the navigation drawer I have 4 options A, B, C and D ... the first one loads FragmentA on my activity and the last 3 load FragmentB ..
FragmentA displays a list of elements and, upon selecting one of these elements FragmentB is used to load its content... I want to change the home (hamburger/drawer) icon on FragmentB for the up icon when initiating from FragmentA (and change the corresponding behavior to make a popstack on select).. I have no problem with this using setDisplayHomeAsUpEnabled(true), but since all this is occurring inside one activity if I then select one other option (say B) from the navigation drawer the up icon will still be showing (it its also showing on the popped fragment)...
if I use setDisplayHomeAsUpEnabled(false) all this do is hide the home/up button from the toolbar, I need to recover the home button and make sure this will be shown when FragmentB is initiated from the drawer menu ...
Does this problem ring a bell to anyone? or am I just using fragments the wrong way? .. any advice will be appreciated
EDIT
this is more or less what I have in code
In Main Activity .. as the onNavigationItemSelected(MenuItem item) for the drawer I have a something like this ...
switch(optionNumber) {
case 0:
fragment = FragmentA.newInstance(optionNumber);
break;
default:
fragment = FragmentB.newInstance(optionNumber);
break;
}
Fragment frag = fragmentManager.findFragmentByTag("current_fragment");
if (frag != null && frag.getClass() == FolderFragment.class){
((FolderFragment)frag).resetScroll();
}
fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
fragmentManager.beginTransaction().replace(R.id.content, fragment, "current_fragment").commit();
which selects the fragment to load according to the option selected..
In FragmentA I'm calling FragmentB with this ..
FragmentB fFragment = FragmentB.newInstance(position);
Bundle args = new Bundle();
args.putString("filter", "something"); fFragment.setArguments(args);
mActivity.getSupportFragmentManager().beginTransaction()
.replace(R.id.flContent, fFragment, "current_fragment")
.addToBackStack(null)
.commit();
Preserving the fragment in the stack
And in fragmentB inside onResume() function I got something like...
String filter = getArguments().getString("filter", null);
if (type != null) {
mActivity.setTitle(title);
mActivity.getSupportActionBar().setDisplayShowHomeEnabled(true);
}else {
/*mActivity.getSupportActionBar().setDisplayHomeAsUpEnabled(false);
mActivity.getSupportActionBar().setDisplayShowHomeEnabled(true);
mActivity.getSupportActionBar().setHomeButtonEnabled(true);
mActivity.getSupportActionBar().setIcon(R.mipmap.ic_menu);*/
}
So When I'm creating fragmentB I check for arguments and see if it comes from fragmentA or not ( I could also check the fragmentmanager backstack and see if there's something)... there I just change the drawer icon with setDisplayShowHomeEnabled(true) ... leaving the back arrow, if I return to FragmentA (via onBackPressed()) FragmentA shows the arrow and I need it to show the original drawer icon ... the same happens if I select an option from the drawer menu ...
Does this gives more clarity to my issue ?... I have some commented code there because it doesn't work .. if I activate the line with setDisplayHomeAsUpEnabled(false).. the icon just disappears from the activity (which is the intended result of the function as far as I know)...
After a while I finally found this post
Switching between Android Navigation Drawer image and Up caret when using fragments
I guess that when involving a Drawer in the interface you might need to handle this issue with that component... this post gave me the answer.
Particular notice to the last comment by Wolfram Rittmeyer