FragmentContainerView使用findNavController

66
我正在使用带有底部导航的Android Navigation组件,lint给出了一个警告,建议将标签替换为,但是当我替换后,findNavController不起作用,并提示我它没有设置NavController。
结果:

我正在使用带有底部导航的Android Navigation组件,lint给出了一个警告,建议将<fragment>标签替换为<FragmentContainerView>,但是当我替换后,findNavController不起作用,并提示我它没有设置NavController。

<androidx.fragment.app.FragmentContainerView
            android:id="@+id/nav_host_fragment"
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:defaultNavHost="true"
            app:navGraph="@navigation/mobile_navigation" />

活动

val navController = findNavController(R.id.nav_host_fragment)
    
    val appBarConfiguration = AppBarConfiguration(
        setOf(
            R.id.navigation_classes, R.id.navigation_schedule, R.id.navigation_settings
        )
    )
    setupActionBarWithNavController(navController, appBarConfiguration)
    navView.setupWithNavController(navController)
}

用“fragment”替换“FragmentContainerView”。 - Mohammed Alaa
13
我不想使用“fragment”,如果我替换它会有一个警告。 - Jimale Abdi
9个回答

170
根据此问题,当使用FragmentContainerView时,在onCreate()中需要使用findFragmentById()查找NavController而不是使用findNavController()
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
这是因为findNavController(R.id.nav_host_fragment)依赖于Fragment的View已经被创建,但是使用FragmentContainerView时并不是这种情况(因为它在内部使用FragmentTransaction来添加NavHostFragment)。
如果您正在使用Fragment 1.4.0或更高版本以及View Binding,则可以通过使用getFragment()方法来大幅简化此过程:
val navController = binding.container.getFragment<NavHostFragment>().navController

1
是的,在 onCreate() 之外,Fragment 的视图将被创建,因此继续调用 findNavController() 是没有问题的。 - ianhanniballake
1
这个答案在Fragment.onCreate()中不起作用。显示NavController在onCreate()之前不可用 - EpicPandaForce
4
如果您在一个Fragment中,您不会使用这里的任何内容,而是应该使用NavHostFragment.findNavController(this) / findNavController() - ianhanniballake
1
我喜欢使用类似于supportFragmentManager这样的魔法变量的引用。 - Chuck
2
@Chuck - 那不是一个“魔术变量” - 这是 Kotlin 代码引用 FragmentActivitygetSupportFragmentManager() API 的方式。 - ianhanniballake
显示剩余14条评论

11

更改此行:

NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);

随着

NavController navController = getNavController();

其中getNavController()看起来像这样:

    // workaround for https://issuetracker.google.com/issues/142847973
    @NonNull
    private NavController getNavController() {
        Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
        if (!(fragment instanceof NavHostFragment)) {
            throw new IllegalStateException("Activity " + this
                    + " does not have a NavHostFragment");
        }
        return ((NavHostFragment) fragment).getNavController();
    }

1
对我来说,这是最好的解决方案。 - alfianrehanusa

4

除了已接受的答案,还有一个小技巧可以使用:

supportFragmentManager.findFragmentById(R.id.navHostMain)?.findNavController()

问候


3
在您的 build.gradle 文件(Module: App)中添加以下行:
implementation "androidx.navigation:navigation-fragment-ktx:2.3.2"

并在活动中使用它

val navController = supportFragmentManager.findFragmentById(R.id.your_id_nav_host_fragment)
            ?.findNavController()

和片段中

val navController = findNavController()

2

我通过扩展程序解决了我的问题:

fun FragmentActivity.findFragmentContainerNavController(@IdRes host: Int):NavController {
    try {
        val navHostFragment = supportFragmentManager.findFragmentById(host) as NavHostFragment
        return navHostFragment.findNavController()
    } catch (e: Exception) {
        throw IllegalStateException("Activity $this does not have a NavController set on $host")
    }
}

1

使用简单的<fragment>标签,而不是<androidx.fragment.app.FragmentContainerView>


0

这里是简单的答案 -

val navHostFragment = supportFragmentManager.findFragmentById(R.id.fragmentContainerView)

作为NavHostFragment

val navController = navHostFragment.navControllermenus.setupWithNavController(navController)


navControllermenus 是什么? - Taslim Oseni

0

有一个更简单的方法可以实现@friederbluemle的答案。一个断言检查就足够了。

NavHostFragment navHostFragment 
    = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
assert navHostFragment != null : "navHostFragment not found";
NavController navController = navHostFragment.getNavController();

-1

我已经将 <androidx.fragment.app.FragmentContainerView> 更改为 <fragment>,并且它对我起作用了。


2
这样做违背了问题的初衷,用户不想使用<fragment>... - thebluepandabear

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接