Navigation Component: How to set drawer with toolbar in each fragment

383 views Asked by At

I'm using navigation component and want to connect drawer layout with toolbar in each fragment, not the activity.

I tried this answer which is called on onViewCreated() but any view referenced from the activity is null. I guess it's because fragment is inflated in the layout before returning from the activity's onCreate method.

I use this extension function to connect the drawer with the fragment's toolbar, I tried to call it from onCreateView() and onViewCreated() but did't work and the activity's drawer layout is always null. I works only if it's called from onStart() but I don't think it's the right way:

private fun AppCompatActivity.setToolbar() {
    setSupportActionBar(binding.toolbar)
    setHasOptionsMenu(true)
    val drawer = findViewById<DrawerLayout>(R.id.drawer)
    binding.toolbar.setupWithNavController(findNavController(), drawer)
}

What's the right place to call this function?

2

There are 2 answers

0
ianhanniballake On BEST ANSWER

When you call setContentView(R.id.activity_layout), the entire view hierarchy is first inflated, then attached to the Activity. It is only after setContentView() returns that findViewById() will find any of the newly inflated views.

When you use the <fragment> tag, the Fragment's view and the views of all of its child fragments are synchronously created as part of that inflation call. This means that setContentView() has not completed by the time the onCreateView() and onViewCreated() methods are called. This is why that calling findViewById() returns null - the activity's view hasn't actually finished being created.

FragmentContainerView was specifically built to avoid these special cases and instead use the same mechanisms as other fragments - namely, it just uses a normal FragmentTransaction to add your Fragment - the same as if you called beginTransaction()+commitNow() in your onCreate() method yourself. This means that the Fragment is not forced to synchronously create its view as part of setContentView(), but can do it alongside every other Fragment after setContentView() returns. This is what allows findViewById() from onCreateView() or onViewCreated() work.

0
Siele Kim On

You can achieve this by simply using an interface which you need to implement in activity. No need to reference activity's drawerLayout from fragment.

Interface like this:

interface DrawerWithToolbar {
    fun setupToolbarDrawer(toolbar: MaterialToolbar)
}

Then in activity:

override fun setupToolbarDrawer(toolbar: MaterialToolbar) {
        toolbar.setupWithNavController(navController,drawerLayout)
    }

In fragment:

(activity as DrawerWithToolbar).setupToolbarDrawer(toolbar)