I'm using new jetpack navigation library. Here I have 3 fragments A, B & C. A is my main fragment. From A fragment navigate to B fragment(A->B). From B to C(B->C). C->A then A->C->B->A->B like this. From whichever fragment I navigate if I press the system back button then I should navigate to A fragment Without having any backstacks pending.
Place fragment A as a start destination and then add them all as top level destinations. For that you would need an AppBarConfiguration:
private lateinit var appBarConfiguration: AppBarConfiguration
//in onCreate or somewhere
appBarConfiguration = AppBarConfiguration(
setOf(
R.id.fragmentA,
R.id.fragmentB,
R.id.fragmentC
)
)
setupActionBarWithNavController(navController, appBarConfiguration)
Related
I'm using Navigation fragment version 2.5.0. As release of version 2.4.0-alpha01, it's suppose to support back stack support for bottom navigation without writing any additional code. But my fragments are re-created everytime while I navigate with bottom navigation.
I'm using single graph, single activity Architecture.
Navigation dependencies
implementation 'androidx.navigation:navigation-fragment-ktx:2.5.0'
implementation 'androidx.navigation:navigation-ui-ktx:2.5.0'
Nav-controller
val navHostFragment = supportFragmentManager.findFragmentById(
R.id.nav_host_container
) as NavHostFragment
navController = navHostFragment.navController
// Setup the bottom navigation view with navController
val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottom_nav)
bottomNavigationView.setupWithNavController(navController)
// Setup the ActionBar with navController and 3 top level destinations
appBarConfiguration = AppBarConfiguration(
setOf(R.id.titleScreen, R.id.leaderboard, R.id.register)
)
setupActionBarWithNavController(navController, appBarConfiguration)
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)
}
I am using the latest Navigation version 2.4.2.
I set up the bottom nav bar with the Navigation component as follow, the same way recommended by google:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val navView: BottomNavigationView = binding.navView
val navController = findNavController(R.id.nav_host_fragment_activity_main)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
val appBarConfiguration = AppBarConfiguration(
setOf(
R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications
)
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
My menu:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/navigation_home"
android:icon="#drawable/ic_home_black_24dp"
android:title="#string/title_home" />
<item
android:id="#+id/navigation_dashboard"
android:icon="#drawable/ic_dashboard_black_24dp"
android:title="#string/title_dashboard"
xmlns:app="http://schemas.android.com/apk/res-auto" />
<item
android:id="#+id/navigation_notifications"
android:icon="#drawable/ic_notifications_black_24dp"
android:title="#string/title_notifications" />
However, when I navigate from one fragment to the other, its onDestroy() is called and when I navigate back to it is recreated.
This is the case for all the fragment in the BottomNavView except the startDestination. The onCreate() for the startDestination is called only once and when navigating away from it, only the onDestroyView() is called. I want this behavior for all the other fragments as well as I need to put code in the onCreate() method and want it to run once once per lifecycle of the app.
Support for multiple backstack arrive with Navigation 2.4.0 so I don't know what's wrong. when calling findNavController.navigate(...), the previous fragment is kept in the backstack and is not destroyed(), and as far as I know the BottomNavBar calls the same method so I can't figure out why each fragment is being created/destroyed upon each navigation.
Me navigating from : Start Fragment -> Dashboard Fragment -> Navigation Fragment -> Start Fragment
All the fragment except the Start Fragment is recreated.
Any help is appreciated.
For anyone looking for an answer to this question. Google replied that it is expected behaviour.
https://issuetracker.google.com/issues/190893266
Edit:
The original question was Is there a way to get a reference to a fragment that is displayed using a BottomNavigationView?. But I've figured some things out and realized I was asking the wrong question.
I'd like to get a reference to a fragment that is being displayed using a BottomNavigationView.
This is how my BottomNavigationView is being setup. It's in onCreate of an Activity.
val navView: BottomNavigationView = findViewById(R.id.nav_view)
val navController = findNavController(R.id.bottom_nav_view_nav_host)
val appBarConfiguration = AppBarConfiguration(setOf(
R.id.navigation_first_list,
R.id.navigation_second
))
setupActionBarWithNavController(navController, appBarConfiguration)
bottomNav.setupWithNavController(navController)
I've tried to get the fragment with bottomNav.findFragment<TheFragmentType>() it throws an exception.
I was asking the wrong question originally. I can just use the navController to call the correct navigation component in order to show the right fragment with a back stack.
val bundle = bundleOf("someId" to "theId")
navController.navigate(R.id.action_navigation_list_to_details, bundle)
I am using Android architecture components with the Single Activity pattern on Android. The navigation pattern I am using is BottomNavigationView.I actually want the parent activity to have no ActionBar but setting my theme to be of type NoActionBar crashes the App. Setting Navigation in Activity has been done as below
val navController = findNavController(R.id.nav_host_fragment)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
val appBarConfiguration = AppBarConfiguration(
setOf(R.id.navigation_popular, R.id.navigation_top_rated, R.id.navigation_favorites)
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
How do I set up bottom navigation to have no actionBar since I wish to have on of the some fragments with ActionBar, like CollapsingToolbarLayout?
I think you found the solution but for the others,
if you want to use the BottomNavigationView with the .NoActionBar theme so you should remove these lines:
val appBarConfiguration = AppBarConfiguration(
setOf(R.id.navigation_popular, R.id.navigation_top_rated, R.id.navigation_favorites)
)
setupActionBarWithNavController(navController, appBarConfiguration)
Using Android Navigation BottomNavigationView. Do not restrict activity with NoActionBar in manifest. Instead from your activity retrieve an instance of your support action bar and use its public method hide()
if (savedInstanceState == null) {
setupBottomNavigationBar()
} // Else, need to wait for onRestoreInstanceState
supportActionBar?.hide()