请注意,我不是在谈论Nested Navigation Graphs . 我特别谈到使用 NavHostFragments
作为其他 NavHostFragments
的子部分,并使用NavigationComponent在子片段和父片段之间来回转换 . 话虽如此...
How do we properly use Navigation Component with NavHostFragments inside other 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>
主活动有 NavHostFragment
,其id为 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
(例如,按一下按钮) . 但等等,还有更多......
What if I would like Fragment B to contain it's own inner NavHostFragment? xml看起来像这样:
<?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
,名为 embeddedNavHostFragment
,它有一个navGraph,如下所示:
<?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
之间导航 . 现在主要问题......
What is the proper way override onSupportNavigateUp() in the MainActivity?
最初,我做了这样的事情:
override fun onSupportNavigateUp(): Boolean {
return findNavController(R.id.navHost).navigateUp()
}
但在某些情况下,这会导致由于堆栈不一致而导致崩溃 . 例如:
-
MainActivity
以navHost
中的片段A
开头 . -
通过
action_fragmentA_to_fragmentB
导航到B
(在embeddedNavHost
中以B1
开头) -
通过
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
}
}
这最终起作用了 . 没有崩溃 . 但是,我只是好奇 if there's a more proper/automated way 处理嵌入式 NavHostFragments
的向上导航 . 这种当前的方式更像是一种解决方法而不是一种适当的解决方案有没有其他 alternatives 如何使这个工作?
另外,我彼此之间'm curious of people' s opinions of NavHostFragments being embedded . 它是否合适?弄清楚如何相应地处理后退按钮并不是一个简单或直接的解决方案,因为没有关于将 NavHostFragments
嵌入彼此并在父片段和子片段之间来回导航的文档 . 所以,我'm wondering if the reason why there is no documentation is because maybe it'是一个不正确的(或意外的)使用NavigationComponent,因此 not 推荐 .
如果您想看看我的示例项目,请转到here