请注意,我在这里不是在谈论Nested Navigation Graphs。我特别在谈论使用NavHostFragments
作为其他NavHostFragments
的子节,以及使用NavigationComponent在子片段和父片段之间来回转换。话虽这么说...
我们如何在其他NavHostFragments内部的NavHostFragments中正确使用导航组件?
例如:假设我有一个MainActivity
,其布局如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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"
android:orientation="vertical"
tools:context=".MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
style="@style/Toolbar"/>
</android.support.design.widget.AppBarLayout>
<fragment
android:id="@+id/navHost"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />
</LinearLayout>
主要活动的ID为NavHostFragment
的{{1}}使用导航图navHost
,如下所示:
nav_graph
实质上,<?xml version="1.0" encoding="utf-8"?>
<navigation
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:id="@+id/nav_graph"
app:startDestination="@id/fragmentA">
<fragment
android:id="@+id/fragmentA"
android:name="com.example.nestednavfragmentstest.FragmentA"
android:label="FragmentA"
tools:layout="@layout/fragment_a">
<action android:id="@+id/action_fragmentA_to_fragmentB" app:destination="@id/fragmentB"/>
</fragment>
<fragment
android:id="@+id/fragmentB"
android:name="com.example.nestednavfragmentstest.FragmentB"
android:label="FragmentB"
tools:layout="@layout/fragment_b"/>
</navigation>
可以从navHost
导航到FragmentA
(例如,单击按钮)。但是等等,还有更多...
如果我想FragmentB
包含它自己的内部Fragment B
怎么办? xml可能看起来像这样:
NavHostFragment
如您所见,<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Fragment B"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<fragment
android:id="@+id/embeddedNavHostFragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="50dp"
app:defaultNavHost="true"
app:layout_constraintTop_toBottomOf="@id/textView"
app:layout_constraintBottom_toBottomOf="parent"
app:navGraph="@navigation/inner_nav_graph"/>
</android.support.constraint.ConstraintLayout>
有自己的FragmentB
,名为NavHostFragment
,其navGraph如下所示:
embeddedNavHostFragment
如您所见,该内部<?xml version="1.0" encoding="utf-8"?>
<navigation
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:id="@+id/inner_nav_graph"
app:startDestination="@id/innerFragmentB1">
<fragment
android:id="@+id/innerFragmentB1"
android:name="com.example.nestednavfragmentstest.InnerFragmentB1"
android:label="InnerFragmentB1"
tools:layout="@layout/inner_fragment_b1">
<action android:id="@+id/action_innerFragmentB1_to_innerFragmentB2" app:destination="@id/innerFragmentB2"/>
</fragment>
<fragment
android:id="@+id/innerFragmentB2"
android:name="com.example.nestednavfragmentstest.InnerFragmentB2"
android:label="InnerFragmentB2"
tools:layout="@layout/inner_fragment_b2"/>
</navigation>
用于在两个内部片段NavHostFragment
和InnerFragmentB1
之间导航。现在是主要问题...
在InnerFragmentB2
中覆盖onSupportNavigateUp()
的正确方法是什么?
最初,我做了这样的事情:
MainActivity
但是在某些情况下,这会由于后堆栈不一致而导致崩溃。例如:
override fun onSupportNavigateUp(): Boolean {
return findNavController(R.id.navHost).navigateUp()
}
以MainActivity
中的片段A
开头。navHost
导航到action_fragmentA_to_fragmentB
(以B
中的B1
开头)embeddedNavHost
从action_innerFragmentB1_to_innerFragmentB2
导航到B1
(发生在B2
上)embeddedNavHost
从embeddedNavHost
返回到B2
[期望结果])B1
从navHost
返回到B
[期望结果])A
导航到action_fragmentA_to_fragmentB
B
[不期望的结果] 所以最后,我最终做了:
IllegalArgumentException: navigation destination id/action_fragmentA_to_fragmentB
这最终成功了。没有崩溃。但是,我只是想是否有一种更正确/自动的方法来处理嵌入式override fun onSupportNavigateUp(): Boolean {
val hostedFragment = navHost?.childFragmentManager?.primaryNavigationFragment
return when(hostedFragment){
is FragmentB -> {
if(hostedFragment.isInnerFragmentB2Showing()){
findNavController(R.id.embeddedNavHostFragment).navigateUp()
} else {
findNavController(R.id.navHost).navigateUp()
}
}
is FragmentA -> {
findNavController(R.id.navHost).navigateUp()
}
else -> false
}
}
的向上导航。当前的方法感觉更像是一种解决方法,而不是适当的解决方案。还有其他替代方法来使它起作用吗?
此外,我很好奇人们对NavHostFragments
的观点相互嵌入。这是适当的用途吗?弄清楚如何相应地处理后退按钮不是一个简单或直接的解决方案,因为没有关于将NavHostFragments
彼此嵌入并在父片段和子片段之间来回导航的文档。因此,我想知道是否没有文档的原因是因为它可能是对NavigationComponent的不正确(或意外)使用,因此不被推荐。
如果您想看看我的示例项目,请转到here