7

I'm trying to replace all findViewById using View Binding. But, I can't change my NavController code line using View Binding.

val navController = findNavController(this, R.id.mainHostFragment)

to

var binding : ActivityMainBinding
val navController = findNavController(this, binding.mainHostFragment)

How can I do that?

Thaw De Zin
  • 1,409
  • 2
  • 10
  • 18

4 Answers4

6

You can't replace it with View Binding. findNavController does more than finding the view in the layout.

Have a look at the source code here

/**
* Find a {@link NavController} given a local {@link Fragment}.
*
* <p>This method will locate the {@link NavController} associated with this Fragment,
* looking first for a {@link NavHostFragment} along the given Fragment's parent chain.
* If a {@link NavController} is not found, this method will look for one along this
* Fragment's {@link Fragment#getView() view hierarchy} as specified by
* {@link Navigation#findNavController(View)}.</p>
*
* @param fragment the locally scoped Fragment for navigation
* @return the locally scoped {@link NavController} for navigating from this {@link Fragment}
* @throws IllegalStateException if the given Fragment does not correspond with a
* {@link NavHost} or is not within a NavHost.
*/
@NonNull
public static NavController findNavController(@NonNull Fragment fragment) {
Fragment findFragment = fragment;
while (findFragment != null) {
    if (findFragment instanceof NavHostFragment) {
        return ((NavHostFragment) findFragment).getNavController();
    }
    Fragment primaryNavFragment = findFragment.getParentFragmentManager()
            .getPrimaryNavigationFragment();
    if (primaryNavFragment instanceof NavHostFragment) {
        return ((NavHostFragment) primaryNavFragment).getNavController();
    }
    findFragment = findFragment.getParentFragment();
}
// Try looking for one associated with the view instead, if applicable
View view = fragment.getView();
if (view != null) {
    return Navigation.findNavController(view);
}
throw new IllegalStateException("Fragment " + fragment
        + " does not have a NavController set");
}

It does more than just finding the controller. It traverses, creates fragment, creates views and throw an exception.

View binding just generates a binding class with all the views of your layout in it. It is not meant for finding the navigation controller of the app.

Somesh Kumar
  • 8,088
  • 4
  • 33
  • 49
4

Here is my sample code, using view binding & navigation.

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import com.zeddigital.zigmaster.databinding.ActivityMainBinding


class MainActivity : AppCompatActivity() {

    private lateinit var appBarConfiguration: AppBarConfiguration
    private lateinit var binding : ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        /*
        Use view binding in activities
        
        Call the static inflate() method included in the generated binding class. 
        This creates an instance of the binding class for the activity to use.
        Get a reference to the root view by either calling the getRoot() method or using Kotlin property syntax.
        Pass the root view to setContentView() to make it the active view on the screen.*/
        binding = ActivityMainBinding.inflate(layoutInflater)

        val view = binding.root
        setContentView(view)

        setSupportActionBar(binding.appBarMain.toolbar)

        //val navController = findNavController(R.id.nav_host_fragment)
        val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
        val navController = navHostFragment.navController

        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        appBarConfiguration = AppBarConfiguration(setOf(
                R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow), binding.drawerLayout)
        setupActionBarWithNavController(navController, appBarConfiguration)
        binding.navView.setupWithNavController(navController)

    }
}
Bolt UIX
  • 5,988
  • 6
  • 31
  • 58
3

With help in this answer, i find a simple implementation

binding?.apply {
        setContentView(root)
        setSupportActionBar(toolbar)
        navController = (supportFragmentManager
            .findFragmentById(fragmentHost.id) as NavHostFragment)
            .navController
        setupActionBarWithNavController(navController, appBarConfiguration)
        bottom.setupWithNavController(navController)
    }
luisenricke
  • 159
  • 10
3

findNavController(R.id.nav_host_fragment) should come after attaching view to activity like this:

setContentView(binding.root)
val navController: NavController = findNavController(R.id.nav_host_fragment) 

More Here

francis
  • 3,852
  • 1
  • 28
  • 30