gpt4 book ai didi

android - 如何处理多个 NavHosts/NavControllers?

转载 作者:行者123 更新时间:2023-12-02 12:35:49 26 4
gpt4 key购买 nike

我在处理多个 NavHost 时遇到问题。这个问题和问的 here 非常相似。 .我认为这个问题的解决方案也会对我有所帮助,但这是 2017 年的帖子,仍然没有答案。 Android 开发者文档没有帮助,通过网络搜索绝对没有任何帮助。

所以基本上我有一个 Activity 和两个 fragment 。让我们称呼他们
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 显示的列表中所选水果的详细信息。

到目前为止,我们有 Activity -> ListFragment -> DetailFragment。

现在我需要再添加一个 Fragment,称为 GalleryFragment。它是一个简单的 fragment ,显示许多所选水果的图片,并在单击按钮时由 FruitDetailFragment 调用。

这里的问题是:在纵向模式下,我只使用 findNavController().navigate(...)我可以随意浏览 fragment 。但是当我在横向模式下使用平板电脑时,我正在使用该主详细信息流在同一屏幕上显示列表和详细信息。有一个例子说明它是如何工作的 here ,并且我希望 GalleryFragment 替换 FruitDetailFragment,与水果列表共享屏幕,但到目前为止我只能设法使其替换“主导航”流程,占据整个屏幕并将 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 并将其替换为 <fragment> id 'sideFragmentContainer' 而不是整个屏幕(而不是替换 Activity 的 xml 中 id <fragment>fragmentContainer)。

我没有找到关于如何处理多个 NavHost 或 <fragment> 的任何解释。里面 <fragment> .

那么基于此,是否可以使用导航架构并在另一个 fragment 中显示一个 fragment ?我需要多个 NavHost,还是有其他方法?

最佳答案

正如 jsmyth886 所建议的那样, this blog post为我指明了正确的方向。
诀窍是findFragmentById()获取 NavHost直接从 fragment 容器(在这种情况下,与主细节屏幕的其余部分共享屏幕)。这使我能够访问正确的 NavController并按预期导航。
创建第二个 NavGraph 很重要也。

所以快速一步一步:

  • 创建主NavGraph进行所有通常的导航(如果没有 Master Detail Flow,它将如何工作);
  • 创建辅助 NavGraph仅包含可能的 Destinations Master Detail fragment 将访问。没有 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"很重要。然后主从布局将如下所示:

  • <?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。
  • 在代码部分,您应该有一个 bool 标志来验证您的应用程序是否在平板电脑上运行(答案开头提供的链接说明了如何执行此操作)。就我而言,我将它作为 MutableLiveData在我的ViewModel ,这样我可以观察它并相应地更改布局。
  • 如果不是平板电脑(即遵循正常的导航流程),只需调用 findNavController().navigate(R.id.your_action_id_from_detail_to_some_other_fragment) .主导航将使用主 NavController ;
  • 如果是使用 Master Detail Flow 的平板电脑,您必须找到正确的 NavHostNavController通过查找 <fragment>包含它,就像这样:
  • val navHostFragment = childFragmentManager.findFragmentById(R.id. sideFragmentContainer) as NavHostFragment
  • 最后,您可以通过调用 navHostFragment.navController.navigate(R.id.id_of_the_destination) 导航到要显示的 fragment ,将屏幕与主从屏幕的其余部分分开。 .请注意,这里我们不调用 Actions ,我们称之为Destination直接地。

  • 就是这样,比我想象的要简单。感谢 Lara Martín 的博文和 jsmyth886 为我指明了正确的方向!

    关于android - 如何处理多个 NavHosts/NavControllers?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56804449/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com