[英]How to handle multiple NavHosts/NavControllers?
我在处理多个 NavHost 时遇到问题。 这个问题与这里提出的问题非常相似。 我认为这个问题的解决方案对我也有帮助,但它是 2017 年的帖子,仍然没有答案。 Android 开发人员文档无济于事,通过网络搜索绝对没有任何可能有帮助的内容。
所以基本上我有一个活动和两个片段。 让我们称它们为 FruitsActivity、FruitListFragment、FruitDetailFragment,其中 FruitsActivity 没有相关代码,其 xml 布局由<fragment>
标记组成,用作NavHost
,如下所示:
<fragment
android:id="@+id/fragmentContainer"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/fruits_nav_graph"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
FruitListFragment 是我的 NavGraph 的 startDestination,它处理来自服务器的水果列表。 FruitDetailFragment 显示有关在 FruitListFragment 显示的列表中选择的 Fruit 的详细信息。
到目前为止,我们有 Activity -> ListFragment -> DetailFragment。
现在我需要再添加一个 Fragment,称为 GalleryFragment。 这是一个简单的片段,显示所选水果的许多图片,并在单击按钮时由 FruitDetailFragment 调用。
这里的问题是:在纵向模式下,我只需使用findNavController().navigate(...)
并按照我想要的方式浏览 Fragment。 但是当我在横向模式下使用平板电脑时,我正在使用主详细信息流在同一屏幕上显示列表和详细信息。 还有就是它是如何工作的例子在这里,我想GalleryFragment更换FruitDetailFragment,水果列表共享屏幕,但到目前为止,我只能设法使其代替“主导航”流动,占据整个screen 并将 FruitListFragment 发送到 Back Stack。
我已经尝试使用findNavController()
方法,但是无论我从哪里调用它,我都只能始终获得相同的NavController
,并且它始终以相同的线性方式导航。 我试图实现我自己的 NavHost,但我得到并错误“找不到 androidx.navigation.NavHost 的类文件”。
这是我的 FruitsActivity 的 xml:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/fragmentContainer"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/listing_nav_graph"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
</layout>
这是横向模式下 FruitListActivity 的 xml(纵向模式下只有 RecyclerView):
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvFruits"
android:layout_weight="3"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="8dp"/>
<FrameLayout
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/sideFragmentContainer"
android:name="fruits.example.FruitDetailFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
</LinearLayout>
</RelativeLayout>
</layout>
现在我想调用 GalleryFragment 并让它只替换 id 'sideFragmentContainer' 的<fragment>
而不是整个屏幕(而不是替换 Activity xml 中 id fragmentContainer
的<fragment>
)。
我没有找到如何处理多个NavHosts或任何解释<fragment>
内<fragment>
。
那么基于此,是否可以使用导航架构并在另一个 Fragment 中显示一个 Fragment? 为此我需要多个 NavHost,还是有其他方法?
正如jsmyth886所建议的, 这篇博文为我指明了正确的方向。 诀窍是findFragmentById()
直接从片段容器中获取NavHost
(在这种情况下,与主细节屏幕的其余部分共享屏幕的那个)。 这使我能够访问正确的NavController
并按预期进行导航。 创建第二个NavGraph
也很重要。
所以一个快速的一步一步:
NavGraph
以进行所有常规导航(没有 Master Detail Flow 时如何工作);NavGraph
包含 Master Detail 片段将访问的可能Destinations
的辅助NavGraph
。 没有Actions
连接,只有Destinations
。<fragment>
容器中,设置如下属性:
<fragment
android:id="@+id/fragmentContainer"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/main_nav_graph"
app:defaultNavHost="true"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
app:defaultNavHost="true"
很重要。 然后 Master Detail 布局将如下所示:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvFruits"
android:layout_weight="3"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="8dp"/>
<FrameLayout
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/sideFragmentContainer"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/secondary_nav_graph"
app:defaultNavHost="false"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
</LinearLayout>
</RelativeLayout>
</layout>
app:defaultNavGraph
很重要,在这里将其设置为 false。MutableLiveData
放在我的ViewModel
,这样我就可以观察它并相应地更改布局。findNavController().navigate(R.id.your_action_id_from_detail_to_some_other_fragment)
。 主导航将使用主NavController
;<fragment>
来找到正确的NavHost
和NavController
,如下所示:val navHostFragment = childFragmentManager.findFragmentById(R.id. sideFragmentContainer) as NavHostFragment
navHostFragment.navController.navigate(R.id.id_of_the_destination)
导航到要显示的 Fragment,将屏幕与主详细信息屏幕的其余部分navHostFragment.navController.navigate(R.id.id_of_the_destination)
。 请注意,这里我们没有调用Actions
,而是直接调用Destination
。就是这样,比我想象的要简单。 感谢 Lara Martín 的博文和 jsmyth886 为我指出正确的方向!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.