android - 具有多个堆栈的 Android JetPack 导航
问题描述
我正在使用version 1.0.0-alpha04
带有底部导航的 Jetpack Navigation。它可以工作,但导航不正确。例如,如果我有选项卡 A 和选项卡 B,从选项卡 AI 转到页面 C,然后从那里转到选项卡 B 并再次返回选项卡 A,我将在选项卡 A 中看到根片段,而不是页面 C不是我所期望的。
我正在寻找一种解决方案,为每个选项卡提供不同的堆栈,因此当我回到它时,每个选项卡的状态都会被保留,而且我不喜欢将所有这些片段保留在内存中,因为它有一个坏的对性能的影响,在喷气背包导航之前,我使用了这个库https://github.com/ncapdevi/FragNav,这正是它的作用,现在我正在寻找与喷气背包导航相同的东西。
解决方案
编辑 2:虽然仍然没有一流的支持(截至撰写本文时),但 Google 现在已经更新了他们的示例,并提供了一个他们认为现在应该如何解决的示例:https ://github.com/googlesamples/android-architecture-组件/树/主/NavigationAdvancedSample
主要原因是您只使用一个NavHostFragment
来保存应用程序的整个后台堆栈。
解决方案是每个选项卡都应该拥有自己的后台堆栈。
- 在您的主布局中,用
FrameLayout
. - 每个选项卡片段都是一个
NavHostFragment
并包含自己的导航图,以使每个选项卡片段都有自己的后退堆栈。 - 添加一个
BottomNavigationView.OnNavigationItemSelectedListener
toBottomNavigtionView
来处理每个 FrameLayout 的可见性。
这也照顾了您的“...我不喜欢将所有这些片段保存在内存中...”,因为NavHostFragment
默认情况下使用Navigation fragmentTransaction.replace()
,即您将始终只有与NavHostFragment
s 一样多的片段。其余的只是在导航图的后面堆栈中。
编辑:谷歌正在开发本地实现https://issuetracker.google.com/issues/80029773#comment25
更详细
假设您有BottomNavigationView
2 个菜单选项,Dogs
并且Cats
.
<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.xml
和cat_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>
和对应的 for cat_navigation_graph
。
在您的activity_main.xml
中,添加 2NavHostFragment
秒
<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>
并在下面为您的 cat 添加相应的内容NavHostFragment
。在你的猫框架布局上,设置android:visibility="invisible"
现在,在你MainActivity
的onCreateView
你可以
bottom_navigation_view.setOnNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.dogMenu -> showHostView(host = 0)
R.id.catMenu -> showHostView(host = 1)
}
return@setOnNavigationItemSelectedListener true
}
所做showHostView()
的只是切换FrameLayout
包装NavHostFragment
s 的 s 的可见性。所以一定要以某种方式保存它们,例如onCreateView
val hostViews = arrayListOf<FrameLayout>() // Member variable of MainActivity
hostViews.apply {
add(findViewById(R.id.frame_dog))
add(findViewById(R.id.frame_cat))
}
现在很容易切换hostViews
应该可见和不可见的。
推荐阅读
- windows - Windows 任务计划程序 - 不间断运行任务
- javascript - hide or remove a specific arc in canvas html5
- php - 如何在单击按钮时删除自定义元框?
- python - 将计数器对象的元素相乘
- ruby-on-rails - 使用 Elm 和 Rails 成功运行项目的最小 CircleCI 2 config.yml
- android - 如果 RecyclerView 在 NestedScrollView 内,findLastVisibleItemPosition 返回错误值
- r - 根据第二个数据框的日期范围计算平均浓度
- python - Python - 手动包装一个方法(具体来说,我问的是 robert kern 的 line-profiler )
- c# - 低负载下与数据库的连接问题(dotnet core)
- json - 如何动态地将数据插入 JSON 文件?