FragmentContainerView using findNavController
As per this issue, when using FragmentContainerView
, you need to find the NavController
using findFragmentById()
rather than using findNavController()
when in onCreate()
:
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
This is because findNavController(R.id.nav_host_fragment)
relies on the Fragment's View to already be created which isn't the case when using FragmentContainerView
(as it uses a FragmentTransaction
under the hood to add the NavHostFragment
).
If you are using Fragment 1.4.0 or higher and View Binding, you can simply this considerably by using the getFragment()
method:
val navController = binding.container.getFragment<NavHostFragment>().navController
FragmentContainerView as NavHostFragment
Due to this bug-report:
https://issuetracker.google.com/issues/142847973
This is the only way (currently):
val navHostFragment = supportFragmentManager
.findFragmentById(R.id.my_nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
(Java):
NavHostFragment navHostFragment =
(NavHostFragment) getSupportFragmentManager()
.findFragmentById(R.id.my_nav_host_fragment);
NavController navController = navHostFragment.getNavController();
findNavController() in Fragment gives does not have a NavController set error
I've downloaded an example from Github that helped me fix this problem.
According to the example this code worked for me:
class DashboardActivity : BaseActivity() {
private lateinit var navController: NavController
private lateinit var appBarConfiguration: AppBarConfiguration
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_dashboard)
val navHostFragment = supportFragmentManager.findFragmentById(
R.id.dashboardNavHostFragment
) as NavHostFragment
navController = navHostFragment.navController
// Setup the bottom navigation view with navController
val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottomNavigationView)
bottomNavigationView.setupWithNavController(navController)
// Setup the ActionBar with navController and 2 top level destinations
appBarConfiguration = AppBarConfiguration(
setOf(R.id.scanFragment, R.id.profileFragment)
)
setupActionBarWithNavController(navController, appBarConfiguration)
}
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp(appBarConfiguration)
}
}
NavHostFragment vs FragmentContainerView [Android]
The FragmentContainerView
is a customized Layout designed specifically as the container for Fragments. The NavHostFragment
is responsible for swapping destinations in the Navigation component.
You can use:
<fragment
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/xxxxx"
app:defaultNavHost="true"
..>
and:
val navController = findNavController(R.id.nav_host_fragment)
Or you can use:
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/xxxx"
app:defaultNavHost="true"
..>
with:
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
Get current fragment displayed in FragmentContainerView from MainActivity
You could add a OnDestinationChangedListener
to the NavController
inside you MainActivity
navController.addOnDestinationChangedListener { _, destination, _ ->
if(destination.id == R.id.your_savable_fragment) {
button.text = "Save"
//....
}
if(destination.id == R.id.your_editable_fragment) {
button.text = "Edit"
//....
}
}
Using FragmentContainerView with Navigation component?
Important! There are known issues with different versions of FragmentContainerView
. See the changelog before using. Read through bug fixes and use a recent version of the library.
For now, you should also declare dependency on Fragment 1.2.0-beta02 as it includes a fix for this use case.
implementation "androidx.fragment:fragment:1.2.0-beta02"
Version 1.2.0-beta02
October 11, 2019
Bug fixes
Fixed an issue where Fragment's
onInflate()
did not receive proper attributes fromFragmentContainerView
, breaking cases such asNavHostFragment
. (b/142421837)
Source: https://developer.android.com/jetpack/androidx/releases/fragment#1.2.0-beta02
Using navigation component with bottom navigation bar by using FragmentContainerView tag
As per the Setting up bottom navigation guide:
Note: Setting up bottom navigation requires that you also set up your navigation graph and menu xml as described in Tie destinations to menu items.
That section specifically states that the android:id
of your destination in your navigation graph XML file needs to match the android:id
of the menu item in your menu XML file.
In your case, your navigation XML uses android:id="@+id/fragmentLibrary"
, android:id="@+id/fragmentTransaction"
, and android:id="@+id/fragmentAccount"
, so your menu items should change to use those same IDs.
How to get navController inside activity?
A note from the navigation component guide
Note: The Navigation component is designed for apps that have one main activity with multiple fragment destinations. The main activity is associated with a navigation graph and contains a NavHostFragment that is responsible for swapping destinations as needed. In an app with multiple activity destinations, each activity has its own navigation graph.
You shouldn't use the navigation component to navigate from one activity to another. It is made to swap fragments on a Fragment container.
You can get navController
inside activity
using
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
You also have to add android:name="androidx.navigation.fragment.NavHostFragment"
to your fragment container
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
Related Topics
What Is the Class R in Android
How to Determine If One of My Activities Is in the Foreground
Toolbar Navigation Icon Never Set
Passing Argument to Dialogfragment
Sqlite Android Database Cursor Window Allocation of 2048 Kb Failed
Download Files and Store Them Locally with Phonegap/Jquery Mobile Android and iOS Apps
Opening Android Settings Programmatically
How to Customize Item Background and Item Text Color Inside Navigationview
Programmatically Getting the Gateway and Subnet Mask Details
Programmatically Relaunch/Recreate an Activity
Android: Resize Only Parts of View with Soft Keyboard on Screen
Android Adb Devices Unauthorized
Show Icon in Actionbar/Toolbar with Appcompat-V7 21
How to Re-Sign an .Apk with a Different Certificate Than What It Came With
Set the Layout Weight of a Textview Programmatically