I have 2 items in my BottomNavigationView:
<item
android:id="#+id/first_fragment"
android:enabled="true"
android:icon="#drawable/ic_round_home"
android:title="#fragment_first_title" />
<item
android:id="#+id/second_fragment"
android:enabled="true"
android:icon="#drawable/ic_round_confirmation_number"
android:title="#string/fragment_second_title" />
I have setup my BottomNavigationView to work with the NavController:
binding.bottomNavigationBar.setupWithNavController(navController)
I also happen to have a thirdFragment which is not included in the BottomNavigationView. So, the scenario is I first navigate from firstFragment to thirdFragment. Then from there, I navigate to secondFragment:
findNavController().navigate(thirdFragmentDirections.actionThirdFragmentToSecondFragment())
Now that I've land on secondFragment, selecting firstFragment in BottomNavigationView won't navigate to it! I know it has something to do with multiple backstacks feature in navigation component, but the more I search about it the more I get confused.
To avoid this behavior, we can setup the BottomNavigationView in the following way:
NavigationUI.setupWithNavController(binding.bottomNavigationBar, navController, false)
Related
I have a fragment in bottom navigation when try to launch new fragment with same id using navigation controller instead of launching new fragment it redirects me to bottom navigation tab.
here is my code
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/home_navigation"
app:startDestination="#id/splashFragment">
<fragment
android:id="#+id/baseTabsFragment"
android:name="com.abc.abc.fragment.BaseTabsFragment"
android:label="BaseTabsFragment"
tools:layout="#layout/fragment_common_tabs">
<action
android:id="#+id/action_to_baseFragment"
app:destination="#id/baseTabsFragment"
app:launchSingleTop="false" />
</fragment>
</navigation>
And code to navigate.
findNavController().navigate(R.id.action_to_baseFragment)
Here is a link for more details on this
https://issuetracker.google.com/issues/262076827
Update: I want to avoid the code duplication. I will have same fragments with same actions but different id's looking for a better way to do it.
If i understand correctly, you want to navigate to the same fragment and fragment does not refresh.
If you use navigation component in visual interface you need to pull an arrow from your baseFragment onto baseFragment again, with this you will see an arrow like self pointed. If you don't use visual just paste below code and it will be created.
<action
android:id="#+id/action_to_BaseFragment"
app:destination="#id/baseTabsFragment"
app:popUpTo="#id/baseTabsFragment"
app:popUpToInclusive="true" />
We are using this way because if we want system to navigate, it needs different location then previous, as long as we using same fragment we need to pop the old one.
It happened due to bottom menu. In this case you need to call programmatically to click on that bottom button.
Replace
findNavController().navigate(R.id.action_to_baseFragment)
to
navController.navigate(
R.id.base_graph, null,
NavOptions.Builder().setPopUpTo(navController.graph.startDestinationId, true).build()
)
I'm using the bottom navigation bar with the navigation component
To make the two components work together I called:
bottomNavigationView.setupWithNavController(navController)
Everything works as expected except when I navigate from inside a fragment instead of the bottom navigation bar
"View all" opens the same fragment as "Reports" from the bottom navigation bar
binding.viewAllScansTv.setOnClickListener {
val action = MainFragmentDirections.actionMainFragmentToReportsFragment()
navController.navigate(action)
}
After clicking on "View all", the fragment is opened, the "Reports" button gets selected, however, navigating back "Home" does not work anymore
How can I fix this weird behavior?
The nav graph:
<navigation app:startDestination="#id/mainFragment">
<fragment
android:id="#+id/mainFragment"
android:name="com.package.name.ui.main.MainFragment"
android:label="MainFragment">
<action android:id="#+id/action_mainFragment_to_reportsFragment"
app:destination="#id/reportsFragment" />
</fragment>
</navigation>
The bottom navigation menu:
<menu>
<item
android:id="#+id/mainFragment"
android:title="Home"/>
<item
android:id="#+id/reportsFragment"
android:title="Reports"/>
<item
android:id="#+id/settingsFragment"
android:title="My account"/>
</menu>
As #ianhanniballake mentioned in a comment, a similar question was posted here
What I ended up doing was replacing
val action = MainFragmentDirections.actionMainFragmentToReportsFragment()
navController.navigate(action)
with
val item = mainBottomNavigationView.menu.findItem(R.id.reportsFragment)
NavigationUI.onNavDestinationSelected(item, navController)
So basically I used the NavigationUI API to navigate so that it correctly tracks the back stack. The same NavigationUI API is being used by the BottomNavigationView internally
Setting a click listener on any view should have the same effect as if the user taps the corresponding item in the bottom navigation. So you need to call setSelectedItemId() on the BottomNavigationView.
val mainBottomNav =
activity?.findViewById(R.id.homeBottomNavigation)
mainBottomNav?.selectedItemId = R.id.baseHomeFragment
Your current answer is fine but if you need to pass arguments it wont work, So use this
In the Navigation XML add these lines to the action
app:launchSingleTop="true"
app:popUpTo="#+id/main_navigation"
app:popUpToInclusive="true"
And make sure app:popUpTo="#+id/main_navigation" has the same id as your navigation xml
So the final action should look like:
<action
android:id="#+id/action_cameraFragment_to_searchFragment"
app:destination="#id/searchFragment"
app:launchSingleTop="true"
app:popUpTo="#+id/main_navigation"
app:popUpToInclusive="true"/>
And Navigate normally using the action
val action = CameraFragmentDirections.actionCameraFragmentToSearchFragment()
findNavController().navigate(action)
I updated to Navigation 2.4 (def nav_version = "2.4") and now when tapping on a BottomNavigationView item it does not always highlight the icon or show the fragment the BottomNavigationView item id points to.
There are 3 bottom navigation tabs called Home, Actions, My Progress. From the Home fragment, you can navigate to SubFragment.
So the flow might be to start at Home --> go to SubFragment --> go to Actions with the BottomNavigationView --> and then tap on Home to go back. What this did before the update was open the Home fragment (desired behavior). Now when tapping on the Home icon it shows SubFragment and does not highlight the icon.
More details
This is the navController setup:
bottomNavigationView = findViewById(R.id.bottom_navigation_view)
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
bottomNavigationView.setupWithNavController(navController)
The nav_graph structure is like this:
<fragment
android:id="#+id/home"
android:name="com.example.app.home"
android:label="Home"
tools:layout="#layout/home"
<action
android:id="#+id/action_home_fragment_to_sub_fragment"
app:destination="#id/sub_fragment"/>
</fragment>
<fragment
android:id="#+id/subfragment"
android:name="com.example.app.subfragment"
android:label="Sub Fragment"
tools:layout="#layout/subfragment" />
<fragment
android:id="#+id/actions"
android:name="com.example.app.actions"
android:label="Actions"
tools:layout="#layout/actions" />
<fragment
android:id="#+id/myprogress"
android:name="com.example.app.myprogress"
android:label="My Progress"
tools:layout="#layout/myprogress" />
The menu items id's for the BottomNavigationView are identical to nav_graph.
I thought the issue might be with the nav_graph structure not playing well with the new SDK, so I tried adjusting the structure of the nav_graph so that each navigation tab was within its own like this question answer has setup. It highlights the tab with this approach but still does not navigate to Home like the example above. Only to SubFragment.
Ideas on what I might be missing are appreciated!
Haven't figured out a fix for the issue yet, so downgraded to def nav_version = "2.3.5" and navigation works properly again.
This is the version before Navigation 2.4 as mentioned by # ianhanniballake above in comments.
I also came across with this issue. It is not a bug in the library.
Actually, when you link menu.xml with nav_graph.xml
You only specified only one fragmentId for each destination. Therefore, it is natural for icon not to change its current state when subfragment is selected.
Instead, you should use nested navigation graphs and use the id of that graph for menu.xml.
<navigation
android:id="#+id/home_destination"
app:startDestination="#id/home" >
<fragment
android:id="#+id/home"
android:name="com.example.app.home"
android:label="Home"
tools:layout="#layout/home"
<action
android:id="#+id/action_home_fragment_to_sub_fragment"
app:destination="#id/sub_fragment"/>
</fragment>
<fragment
android:id="#+id/subfragment"
android:name="com.example.app.subfragment"
android:label="Sub Fragment"
tools:layout="#layout/subfragment" />
</navigation>
<fragment
android:id="#+id/actions"
android:name="com.example.app.actions"
android:label="Actions"
tools:layout="#layout/actions" />
<fragment
android:id="#+id/myprogress"
android:name="com.example.app.myprogress"
android:label="My Progress"
tools:layout="#layout/myprogress" />
And when you are specifying the navigation_menu you will do like this:
<item
android:id="#+id/home_destination"
android:icon="#drawable/ic_read_quran"
android:title="#string/read_quran"
app:showAsAction="always" />
I'm using navigation component
'androidx.navigation:navigation-fragment-ktx:2.3.3'
'androidx.navigation:navigation-ui-ktx:2.3.3'
I don't understand why when I'm navigating from my startDestination to the next Fragment
I get a short blinking and I see the previous activity for a couple of millisec.
This doesn't happen when I'm navigating to different fragments.
This happens with and without the navigation animations.
Tried with no previous Activity in stack and it shows the OS home screen.
The navigation.xml file looks like this:
<fragment
android:id="#+id/barcodeScannerFragment"
android:name="com.sightplan.sightplanmobile.feature.barcode_scanner.BarcodeScannerFragment"
android:label="#string/receive_package_barcode_input_view_header_param_title"
tools:layout="#layout/barcode_scanner_fragment_layout">
<action
android:id="#+id/open_receive_package_details"
app:destination="#id/receivePackageDetailsFragment"
app:enterAnim="#anim/slide_left_anim"
app:exitAnim="#anim/wait_anim"
app:popEnterAnim="#anim/wait_anim"
app:popExitAnim="#anim/slide_right_anim" />
</fragment>
<fragment
android:id="#+id/receivePackageDetailsFragment"
android:name="com.sightplan.sightplanmobile.packages.receive_package.ReceivePackageDetailsFragment"
android:label="#string/receive_package_activity_on_create_header_bar_title"
tools:layout="#layout/receive_package_details_fragment_layout">
.......
The navigation (full) desgin looks like this:
And the code for navigating from the startDestination to the Receive Package screen is here:
val action = BarcodeScannerFragmentDirections.openReceivePackageDetails()
Navigation.findNavController(it).navigate(action)
Any ideas on how to solve this?
The problem was due to the theme set on my navigation Activity inside the AndroidManifest.xml.
I had a custom AppTheme with android:windowIsTranslucent set to true.
Removing that solved the issue.
First, some clarifications. After looking at a lot of other related questions let's start with what this is not:
This is not about BottomNavigation
This is not about operating the ViewPager using Navigation Components (like this one)
This questions is about how to use Navigation Components, when Viewpager is one of the components.
The situation is having 3 tabs: TabA, TabB, and TabC
Also having 2 extra fragments: FragA, FragB
How do I connect them all so that:
ViewPagerAdapter is handing TabA, TabB, and TabC
AND nav_praph will handle moving from:
TabA --> FragA
TabB --> FragB
TabC --> FragA (not a typo)
Desired UI behavior
First Option: The best I could get working was define the FragHost inside one of the tabs (e.g. TabA) and then navigate to FragA. Problem was the navigation was done INSIDE the tab. Meaning user would still see the tabs on top, and also can still swipe to the other tabs. Not what I wanted.
Here is a diagram of what worked, but is not what I wanted (the red symbolizes the hosting fragment)
Second option: move the fragHost to the very top, and have it contain the ViewPager so it takes up full screen. Then in the nagGraph mention
<navigation
android:id="#+id/nav_graph"
app:startDestination="#id/tab_a"
>
<fragment
android:id="#+id/tab_a"
android:name="com.myapp.home.views.TabA"
android:layout="#layout/tab_a_layout"
>
<action
android:id="#+id/action_tab_a_to_frag_a"
app:destination="#+id/frag_a"
/>
</fragment>
<fragment
android:id="#+id/frag_a"
android:name="com.myapp.FragA"
android:label="details"
android:layout="#layout/frag_a"
/>
This resulted in an IllegalStateException ... at androidx.fragment.app.FragmentStore.addFragment
Some debugging and I saw it was trying to add TabA twice. I assumed both ViewPagerAdapter and Nav Component are using the Fragment manager.
How do I have normal navigation where you can use the tabs, but clicking on one takes you to another full screen experience on top of the tabs?
Figured out the second option I mentioned is the right way to go.
Writing here in case someone else has the same issue.
Make sure your nav_graph is pointing from the containint fragment of the ViewPager and not from the specific fragment the ViewPager is holding.
So not from TabA but from ContainerFragmentA which hosts the ViewPager
<navigation
android:id="#+id/nav_graph"
app:startDestination="#id/view_pager_hosting_frag"
>
<fragment
android:id="#+id/view_pager_hosting_frag"
android:name="com.myapp.home.views.ViewPagerHostingFrag"
android:layout="#layout/view_pager_layout"
>
<action
android:id="#+id/action_tab_a_to_frag_a"
app:destination="#+id/frag_a"
/>
</fragment>
<fragment
android:id="#+id/frag_a"
android:name="com.myapp.FragA"
android:label="details"
android:layout="#layout/frag_a"
/>
Then you can choose the action you want from any of the tabs to go to the right location