我将Jetpack导航version 1.0.0-alpha04
与底部导航一起使用。它可以工作,但导航无法正确进行。例如,如果我有选项卡A和选项卡B,然后从选项卡AI转到页面C,然后从那里转到选项卡B,然后再次返回到选项卡A,我将在选项卡A中看到根片段,而在页面C中看不到根片段不是我所期望的。
我正在寻找一种解决方案,以使每个选项卡具有不同的堆栈,因此当我返回到每个选项卡时,每个选项卡的状态都将保留,而且我也不喜欢将所有这些片段都保留在内存中,因为它的性能很差。对性能的影响,在jetpack导航之前,我使用了这个库https://github.com/ncapdevi/FragNav,这确实可以实现,现在我在寻找与jetpack导航相同的东西。
任何帮助或建议,将不胜感激。
答案 0 :(得分:5)
编辑2:尽管仍然没有一流的支持(撰写本文时),但Google现在更新了示例,并提供了他们认为应如何解决的示例:{{3} }
主要原因是您仅使用一个NavHostFragment
来容纳应用程序的整个后盖。
解决方案是每个选项卡都应拥有自己的后退堆栈。
FrameLayout
包裹每个标签片段。NavHostFragment
,并包含其自己的导航图,以使每个选项卡片段都具有自己的后向堆栈。BottomNavigationView.OnNavigationItemSelectedListener
添加BottomNavigtionView
来处理每个FrameLayout的可见性。这还可以解决您的“ ...我不希望将所有这些片段都保留在内存中...”,因为默认情况下使用NavHostFragment
进行导航时使用fragmentTransaction.replace()
,即始终只能包含NavHostFragment
个片段。其余的只是在导航图的后堆栈中。
修改:Google正在开发本机实现https://github.com/googlesamples/android-architecture-components/tree/master/NavigationAdvancedSample
更多详细信息
假设您有一个BottomNavigationView
,其中有两个菜单选项,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>
以及对应的cat_navigation_graph
。
在您的activity_main.xml
中,添加2个NavHostFragment
<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"
现在,您可以在MainActivity
的{{1}}中
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()
的{{1}}的可见性。因此,请确保以某种方式保存它们,例如在FrameLayout
NavHostFragment
现在可以轻松切换哪个onCreateView
应该是可见的还是不可见的。
答案 1 :(得分:2)
Android 团队已在最新版本 2.4.0-alpha01 中解决了该问题,现在无需任何解决方法即可支持多个后台堆栈和底部导航。
https://developer.android.com/jetpack/androidx/releases/navigation
答案 2 :(得分:0)
首先,我想对@Algar 的回答进行编辑。您想要隐藏的框架应该有 android:visibility="gone"
而不是 invisible
。在您的主要布局中,您将有这样的原因:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ui.activity.MainActivity">
<include
android:id="@+id/toolbar"
layout="@layout/toolbar_base" />
<FrameLayout
android:id="@+id/frame_home"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2"
>
<fragment
android:id="@+id/home_navigation_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/home_nav" />
</FrameLayout>
<FrameLayout
android:id="@+id/frame_find"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2"
android:visibility="gone">
<fragment
android:id="@+id/find_navigation_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/find_nav" />
</FrameLayout>
...
</LinearLayout>
如果您将 main 包装在 LinearLayout 中,将框架设置为不可见仍然会使该框架计数,因此不会出现 BottomNavigation。
其次,您应该创建一个 NavHostFragment 实例(即:curNavHostFragment)来跟踪单击 BottomNavigation 中的选项卡时哪个 NavHostFragment 可见。 注意:当活动被配置更改破坏时,您可能希望恢复此 curNavHostFragment。这是一个例子:
@Override
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
//if this activity is restored from previous state,
//we will have the ItemId of botnav the has been selected
//so that we can set up nav controller accordingly
switch (bottomNav.getSelectedItemId()) {
case R.id.home_fragment:
curNavHostFragment = homeNavHostFragment;
...
break;
case R.id.find_products_fragment:
curNavHostFragment = findNavHostFragment;
...
break;
}
curNavController = curNavHostFragment.getNavController();