Fragmentcontainerview Using Findnavcontroller

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 from FragmentContainerView, breaking cases such as NavHostFragment. (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



Leave a reply



Submit