具有多个堆栈的Android JetPack导航 [英] Android JetPack navigation with multiple stack
问题描述
我在底部导航中使用Jetpack导航version 1.0.0-alpha04
.它可以工作,但导航无法正确进行.例如,如果我有选项卡A和选项卡B,然后从选项卡AI转到页面C,然后从那里转到选项卡B,然后再次返回到选项卡A,我将在选项卡A中看到根片段,而在页面C中看不到根片段不是我所期望的.
我正在寻找一种解决方案,以使每个选项卡具有不同的堆栈,因此当我返回到每个选项卡时,每个选项卡的状态都将保留,而且我也不喜欢将所有这些片段都保留在内存中,因为它的性能很差.对性能的影响,在jetpack导航之前,我使用了这个库 https://github.com/ncapdevi/FragNav,那确实是做什么的,现在我在寻找与Jetpack导航相同的东西.
I'm using Jetpack Navigation version 1.0.0-alpha04
with bottom navigation. It works but the navigation doesn't happen correctly. For example, if I have tab A and tab B and from tab A I go to Page C and from there I go to tab B and come back to tab A again, I will see root fragment in the tab A and not page C which does not what I expect.
I'm looking for a solution to have a different stack for each tab, so the state of each tab is reserved when I come back to it, Also I don't like to keep all this fragment in the memory since it has a bad effect on performance, Before jetpack navigation, I used this library https://github.com/ncapdevi/FragNav, That does exactly what, Now I'm looking for the same thing with jetpack navigation.
推荐答案
尽管仍然没有一流的支持(在撰写本文时),但Google现在通过示例更新了其示例.他们认为现在应该如何解决: https://github.com/googlesamples/android-architecture-components/tree/master/NavigationAdvancedSample
EDIT 2: Though still no first class support (as of writing this), Google has now updated their samples with an example of how they think this should be solved for now: https://github.com/googlesamples/android-architecture-components/tree/master/NavigationAdvancedSample
主要原因是您仅使用一个NavHostFragment
来容纳应用程序的整个后盖.
The major reason is you only use one NavHostFragment
to hold the whole back stack of the app.
解决方案是每个选项卡都应拥有自己的后退堆栈.
The solution is that each tab should hold its own back stack.
- 在主布局中,每个标签片段都用
FrameLayout
包裹. - 每个选项卡片段都是
NavHostFragment
,并包含其自己的导航图,以使每个选项卡片段都具有自己的后向堆栈. - 在
BottomNavigtionView
中添加BottomNavigationView.OnNavigationItemSelectedListener
以处理每个FrameLayout的可见性.
- In your main layout, wrap each tab fragment with a
FrameLayout
. - Each tab fragment is a
NavHostFragment
and contains its own navigation graph in order to make each tab fragment having its own back stack. - Add a
BottomNavigationView.OnNavigationItemSelectedListener
toBottomNavigtionView
to handle the visibility of each FrameLayout.
这也可以解决您的"...我不希望将所有这些片段都保留在内存中...",因为默认情况下,使用NavHostFragment
进行导航时会使用fragmentTransaction.replace()
,即您将始终只有与NavHostFragment
一样多的片段.其余的只是在导航图的后堆栈中.
This also takes care of your "...I don't like to keep all this fragment in memory...", because a Navigation with NavHostFragment
by default uses fragmentTransaction.replace()
, i.e. you will always only have as many fragments as you have NavHostFragment
s. The rest is just in the back stack of your navigation graph.
修改:Google正在开发本机实现 https://issuetracker.google.com/issues/80029773#comment25
Google is working on a native implementation https://issuetracker.google.com/issues/80029773#comment25
更多详细信息
假设您有一个BottomNavigationView
,其中有两个菜单选项Dogs
和Cats
.
Let's say you have a BottomNavigationView
with 2 menu choices, Dogs
and 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
.
Then you need 2 navigation graphs, say dog_navigation_graph.xml
and 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>
以及对应的cat_navigation_graph
.
在您的activity_main.xml
中,添加2个NavHostFragment
s
In your activity_main.xml
, add 2 NavHostFragment
s
<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
相对应的内容.在您的Cat框架布局上,设置android:visibility="invisible"
and underneath add the corresponding for your cat NavHostFragment
. On your cat frame layout, set 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()
的全部工作是切换包裹NavHostFragment
的FrameLayout
的可见性.因此,请确保以某种方式保存它们,例如在onCreateView
All that showHostView()
is doing is toggling the visibility of your FrameLayout
s that are wrapping the NavHostFragment
s. So make sure to save them in some way, e.g. in onCreateView
val hostViews = arrayListOf<FrameLayout>() // Member variable of MainActivity
hostViews.apply {
add(findViewById(R.id.frame_dog))
add(findViewById(R.id.frame_cat))
}
现在很容易切换哪个hostViews
应该是可见的还是不可见的.
Now it's easy to toggle which hostViews
should be visible and invisible.
这篇关于具有多个堆栈的Android JetPack导航的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!