导航组件:找不到NavController

时间:2018-12-23 09:25:01

标签: android navigation android-jetpack

我正在使用导航组件在我的应用中进行导航。它在片段内部运行良好,但是在保存实际导航主机的活动中找不到导航主机。

当用户单击FAB(我包含在Main活动的XML中)时,我试图打开一个新片段。当我调用findNavController()时,找不到控制器。导航主机控制器位于XML布局中。我不明白为什么找不到它。

MainActivity

class MainActivity : AppCompatActivity(), OnActivityComponentRequest {
    override fun getTabLayout(): TabLayout {
        return this.tabLayout
    }

    override fun getFap(): FloatingActionButton {
        return this.floatingActionButton
    }

    private lateinit var tabLayout: TabLayout
    private lateinit var floatingActionButton: FloatingActionButton

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setSupportActionBar(toolbar)
        this.tabLayout = tabs
        this.floatingActionButton = fab

        fab.setOnClickListener {

         it.findNavController().navigate(R.id.addNewWorkoutFragment)

        }
    }
}

活动主XML

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".domain.MainActivity"
        android:animateLayoutChanges="true">

    <com.google.android.material.appbar.AppBarLayout
            android:layout_height="wrap_content"
            android:layout_width="match_parent"
            android:theme="@style/AppTheme.AppBarOverlay">

        <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="?attr/colorPrimary"
                app:layout_scrollFlags="scroll|enterAlways"
                app:popupTheme="@style/AppTheme.PopupOverlay"/>

        <com.google.android.material.tabs.TabLayout
                android:id="@+id/tabs"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">

            <com.google.android.material.tabs.TabItem
                    android:text="Test 1"
                    android:layout_height="match_parent"
                    android:layout_width="match_parent"/>

            <com.google.android.material.tabs.TabItem
                    android:text="Test 2"
                    android:layout_height="match_parent"
                    android:layout_width="match_parent"/>
        </com.google.android.material.tabs.TabLayout>

    </com.google.android.material.appbar.AppBarLayout>

      <fragment
        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/main_navigation" />


    <com.google.android.material.bottomappbar.BottomAppBar
            android:id="@+id/bar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom"/>


    <com.google.android.material.floatingactionbutton.FloatingActionButton
            android:id="@+id/fab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_anchorGravity="right|top"
            app:layout_anchor="@+id/bar"
            android:src="@drawable/ic_add_black_24dp"/>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

8 个答案:

答案 0 :(得分:4)

直到我设法以这种方式获取navController之前,我都得到了相同的理解:

val navHostFragment = supportFragmentManager.findFragmentById(R.id.my_fragment_container_view_id) as NavHostFragment
val navController = navHostFragment.navController

从此answer获得:

在找到导航控制器之前,如果使用绑定,则需要设置视图:

binding = BaseLayoutBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)

如果不是:

setContentView(R.layout.activity_main)

对片段使用相应的绑定。

答案 1 :(得分:1)

尝试像在onStart中那样在Activity的onCreate中设置Fab按钮的onClickListener,这只是使View膨胀而没有设置NavHostController。因此,如果您在活动的onStart中设置onClickListener将会按预期工作。

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    setSupportActionBar(toolbar)
    this.tabLayout = tabs
    this.floatingActionButton = fab
  }

override fun onStart() {
    super.onStart()
    floatingActionButton.setOnClickListener {
      it.findNavController().navigate(R.id.addNewWorkoutFragment)
    }
  }

答案 2 :(得分:1)

问题可能是FAB已添加到活动中,或者是与NavHost片段使用的片段不同的片段。在这种情况下,当您调用it.findNavController()时,找不到导航控制器。

您可以检查您的FAB是否属于NavHost提取的片段,也可以调用Activity的findNavController(<id>)并将您要查找的片段的ID传递给它

override fun onCreate(savedInstanceState: Bundle?) {
        ...
        fab.setOnClickListener {
            findNavController(R.id.nav_host_fragment)
                .navigate(R.id.R.id.addNewWorkoutFragment)

        }
    }

答案 3 :(得分:1)

您仍然可以通过oncreate来获得访问权限

    //the id would be the id of the Fragment Element In Your Activity XML File
    val navGraph = Navigation.findNavController(this, R.id.activity_main)
    binding.mainFab.setOnClickListener {
        navGraph.navigate(R.id.destinationFragment)
    }

答案 4 :(得分:0)

结果证明该活动包含导航控制器...没有导航组件。

解决方案是将NavController手动设置为活动中包含的每个视图。

val navController = findNavController(R.id.nav_host_fragment)
Navigation.setViewNavController(fab, navController)

现在这可以工作:

fab.setOnClickListener {

    it.findNavController().navigate(R.id.addNewWorkoutFragment)

}

我仍然不明白为什么这样做会起作用,所以任何解释都将不胜感激:)

到目前为止,Android API根本没有多大意义。

来源:Navigate to fragment on FAB click (Navigation Architecture Components)

答案 5 :(得分:0)

在Java中,您可以通过以下方式在活动中找到NavController

Navigation.findNavController(this,R.id.nav_host).navigate(R.id.YourFragment);

答案 6 :(得分:0)

我发现此答案很有帮助。在您的活动中粘贴此代码

Navigation.findNavController(this, R.id.nav_host_fragment).navigate(R.id.yourDestination)

答案 7 :(得分:0)

这是 Kotlin 的扩展版本:

CMakeLists.txt

fun AppCompatActivity.findNavController( @IdRes navHostViewId: Int ): NavController { val navHostFragment = supportFragmentManager.findFragmentById(navHostViewId) as NavHostFragment return navHostFragment.navController } 是您的 navHostViewId 的 ID。