我正在使用导航组件在我的应用中进行导航。它在片段内部运行良好,但是在保存实际导航主机的活动中找不到导航主机。
当用户单击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>
答案 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。