具有多个堆栈的Android JetPack导航

问题描述 投票:5回答:1

我正在使用带底部导航的Jetpack Navigation version 1.0.0-alpha04。它工作但导航没有正确发生。例如,如果我有选项卡A和选项卡B,并从选项卡AI转到页面C,然后从那里我转到选项卡B并再次返回选项卡A,我将在选项卡A中看到根片段而不是页面C不是我所期待的。

我正在寻找一个解决方案,为每个选项卡提供不同的堆栈,因此当我回到它时,每个选项卡的状态都是保留的。此外,我不喜欢将所有这些片段保留在内存中,因为它有一个坏的对性能的影响,在jetpack导航之前,我使用了这个库https://github.com/ncapdevi/FragNav,这确实是什么,现在我正在寻找与jetpack导航相同的东西。

任何帮助或建议将不胜感激。

android android-architecture-components android-jetpack android-architecture-navigation
1个回答
6
投票

编辑2:虽然仍然没有一流的支持(截至撰写本文时),谷歌现在更新了他们的样本,并举例说明他们认为现在应该如何解决这个问题:https://github.com/googlesamples/android-architecture-components/tree/master/NavigationAdvancedSample


主要原因是你只使用一个NavHostFragment来保存应用程序的整个后台。

解决方案是每个选项卡应该拥有自己的后端堆栈。

  • 在主布局中,使用FrameLayout包装每个选项卡片段。
  • 每个选项卡片段都是一个NavHostFragment,并包含自己的导航图,以使每个选项卡片段具有自己的后栈。
  • BottomNavigationView.OnNavigationItemSelectedListener添加到BottomNavigtionView以处理每个FrameLayout的可见性。

这也照顾你的“......我不喜欢将所有这些片段保存在内存中......”,因为默认情况下使用NavHostFragment的导航使用fragmentTransaction.replace(),即你总是只有NavHostFragments那么多的片段。其余的只是在导航图的后堆栈中。

编辑:Google正在开发本机实现https://issuetracker.google.com/issues/80029773#comment25


更详细

假设你有一个有两个菜单选择的BottomNavigationViewDogsCats

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/dogMenu"
        .../>

    <item android:id="@+id/catMenu"
        .../>
</menu>

然后你需要2个导航图,比如dog_navigation_graph.xmlcat_navigation_graph.xml

dog_navigation_graph可能看起来像

<navigation
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/dog_navigation_graph"
    app:startDestination="@id/dogMenu">
</navigation>

和相应的cat_navigation_graph

在你的activity_main.xml中,添加2个NavHostFragments

<FrameLayout
    android:id="@+id/frame_dog"
    ...>

    <fragment
        android:id="@+id/dog_navigation_host_fragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:navGraph="@navigation/dog_navigation_graph"
        app:defaultNavHost="true"/>
</FrameLayout>

并在下面为您的猫NavHostFragment添加相应的。在您的猫框架布局上,设置android:visibility="invisible"

现在,在你的MainActivityonCreateView你可以

bottom_navigation_view.setOnNavigationItemSelectedListener { item ->
    when (item.itemId) {
        R.id.dogMenu -> showHostView(host = 0)
        R.id.catMenu -> showHostView(host = 1)
    }
    return@setOnNavigationItemSelectedListener true
}

所有showHostView()正在做的是切换包裹FrameLayouts的NavHostFragments的可见性。因此,请务必以某种方式保存它们,例如在onCreateView

val hostViews = arrayListOf<FrameLayout>()  // Member variable of MainActivity
hostViews.apply {
    add(findViewById(R.id.frame_dog))
    add(findViewById(R.id.frame_cat))
}

现在很容易切换哪些hostViews应该是可见的和不可见的。

© www.soinside.com 2019 - 2024. All rights reserved.