首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >安卓JetPack多栈导航

安卓JetPack多栈导航
EN

Stack Overflow用户
提问于 2018-08-06 20:40:29
回答 3查看 11K关注 0票数 14

我正在使用带有底部导航的Jetpack导航version 1.0.0-alpha04。它可以工作,但导航不能正确进行。例如,如果我有tab A和tab B,从tab A转到Page C,然后从那里转到tab B并再次返回到tab A,我将在tab A而不是page C中看到根片段,这并不是我所期望的。

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

EN

回答 3

Stack Overflow用户

发布于 2018-09-03 17:06:08

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

主要原因是您只使用一个NavHostFragment来容纳整个应用程序的后端堆栈。

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

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

这也照顾到了你的"...I不喜欢在内存中保存所有这些片段...“,因为默认情况下,使用NavHostFragment的导航使用fragmentTransaction.replace(),也就是说,你总是只有和你的NavHostFragment一样多的片段,其余的只是在你的导航图的后栈中。

谷歌编辑:正在开发一个原生实现的https://issuetracker.google.com/issues/80029773#comment25

更多详细信息

假设您有一个带有两个菜单选项的BottomNavigationViewDogsCats

代码语言:javascript
复制
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/dogMenu"
        .../>

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

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

dog_navigation_graph可能如下所示

代码语言:javascript
复制
<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

代码语言:javascript
复制
<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"

现在,在你的MainActivityonCreateView中,你可以

代码语言:javascript
复制
bottom_navigation_view.setOnNavigationItemSelectedListener { item ->
    when (item.itemId) {
        R.id.dogMenu -> showHostView(host = 0)
        R.id.catMenu -> showHostView(host = 1)
    }
    return@setOnNavigationItemSelectedListener true
}

showHostView()所做的就是切换包装NavHostFragmentFrameLayout的可见性。因此,请确保以某种方式保存它们,例如在onCreateView

代码语言:javascript
复制
val hostViews = arrayListOf<FrameLayout>()  // Member variable of MainActivity
hostViews.apply {
    add(findViewById(R.id.frame_dog))
    add(findViewById(R.id.frame_cat))
}

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

票数 16
EN

Stack Overflow用户

发布于 2021-06-01 12:01:00

Android团队已经解决了这个问题,在最新的2.4.0-alpha01版本中,现在可以在没有任何解决方法的情况下支持多个backstacks以及底部导航。

https://developer.android.com/jetpack/androidx/releases/navigation

票数 2
EN

Stack Overflow用户

发布于 2021-03-31 14:07:48

首先,我想对@Algar的答案进行编辑。您要隐藏的框架应该具有android:visibility="gone"而不是invisible。这样做的原因是在你的主布局中,你会有这样的东西:

代码语言:javascript
复制
    <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中,将frame设置为不可见仍会使该frame有效,因此main将不会出现。

其次,您应该创建一个NavHostFragment实例(即: curNavHostFragment)来跟踪在单击BottomNavigation中的选项卡时哪个NavHostFragment是可见的。注意:当活动被配置的更改破坏时,您可能希望恢复此curNavHostFragment。这是一个示例:

代码语言:javascript
复制
@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();
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51707889

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档