使用导航组件时如何保留特定屏幕?

How to keep a specific screen when using Navigatioin Component?

我有一个 BottomNavigationView,我正在使用 NavController 切换 menus 并移动 screen

我想知道如何在自由移动菜单时保持特定屏幕。

让我再详细解释一下。

有底部菜单A, B, C。每个都有一个 Fragment 屏幕。

所有菜单和屏幕转换都使用 NavHostNavControllernav_graph

在菜单 C 中,通过 C 屏幕上的 button 显示 dialog

该对话框还链接到 nav_graph

在对话框中选择一个选项后,它会移动到屏幕 D

D屏幕是你写东西的页面。

从现在开始这很重要。

当前菜单是 C,屏幕 D 已打开,正在写入内容。

但是,如果您在写入时转到 another menu,然后 return 到 C,第一个菜单 C 的屏幕 C 会出现,而不是你正在写的屏幕。

在这里,我希望即使我从另一个菜单 return 时,我正在编写的屏幕也能继续显示。

有什么好的方法吗?

作为参考,由于我使用的是mvvm模式和viewmodel,所以我正在写入的屏幕数据似乎保持不变。

谢谢。

nav_graph

<?xml version="1.0" encoding="utf-8"?>
<navigation 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:id="@+id/nav_graph"
    app:startDestination="@id/calendar">

    <!-- menu C screen   -->
    <fragment
        android:id="@+id/write_home"
        android:name="com.example.writeweight.fragment.WriteRoutineHomeFragment"
        android:label="fragment_write_routine_home"
        tools:layout="@layout/fragment_write_routine_home" >
        <action
            android:id="@+id/action_write_home_to_bodyPartDialog"
            app:destination="@id/bodyPartDialog" />
    </fragment>

    <!-- dialog -->
    <dialog
        android:id="@+id/bodyPartDialog"
        android:name="com.example.writeweight.fragment.BodyPartDialogFragment"
        android:label="BodyPartDialogFragment"
        tools:layout="@layout/fragment_body_part_dialog">
        <action
            android:id="@+id/action_bodyPartDialog_to_write"
            app:destination="@id/write"/>
    </dialog>

    <!-- screen D (write page) -->
    <fragment
        android:id="@+id/write"
        android:name="com.example.writeweight.fragment.WriteRoutineFragment"
        android:label="WritingRoutineFragment"
        tools:layout="@layout/fragment_writing_routine">
        <action
            android:id="@+id/action_write_to_workoutListTabFragment"
            app:destination="@id/workoutListTabFragment" />
        <argument
            android:name="title"
            app:argType="string"
            app:nullable="true"
            android:defaultValue="@null"/>
        <argument
            android:name="workout"
            app:argType="string"
            app:nullable="true"
            android:defaultValue="@null"/>
    </fragment>
</navigation>

有两种方法可以解决此问题,要么使用 version_navigation 2.4.0-alpha01,这是最简单的方法,要么使用 NavigationExtensions 要使用 NavigationExtensions,您必须将其添加到您的项目 NavigationExtensions,然后在导航菜单中为每个选项卡创建单独的导航文件。 在主 activity 布局中,将 fragment 替换为 FragmentContainerView 并删除 NavHostFragment。

在主要活动中

class MainActivity : AppCompatActivity(), NavController.OnDestinationChangedListener {
private val viewModel by viewModels<MainViewModel>()
private var currentNavController: LiveData<NavController>? = null

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.main)
    setSupportActionBar(toolbar)

    /*
    appBarConfiguration = AppBarConfiguration(
        // navController.graph,
        setOf(
             R.id.navigate_home, R.id.navigate_collection, R.id.navigate_profile
        ),
        drawerLayout
    )

    setupActionBarWithNavController(navController, appBarConfiguration)
    navView.setupWithNavController(navController)
    bottomNavView.setupWithNavController(navController)

    // make sure appbar/toolbar is not hidden upon fragment switch
    navController.addOnDestinationChangedListener { controller, destination, arguments ->
        if (destination.id in bottomNavDestinationIds) {
            appBarLayout.setExpanded(true, true)
        }
    }
     */
     // Add your tab fragments

    val navGraphIds = listOf(R.navigation.home, R.navigation.albumlist, R.navigation.test)
    val controller = bottomNavView.setupWithNavController(
        navGraphIds = navGraphIds,
        fragmentManager = supportFragmentManager,
        containerId = R.id.nav_host_container,
        intent = intent
    )
    // Whenever the selected controller changes, setup the action bar.
    controller.observe(this, Observer { navController ->

        setupActionBarWithNavController(navController)
        // optional NavigationView for Drawer implementation
        // navView.setupWithNavController(navController)

        addOnDestinationChangedListener(navController)
    })
    currentNavController = controller
}

private fun addOnDestinationChangedListener(navController: NavController) {
    // ensure only one listener is active
    navController.removeOnDestinationChangedListener(this)
    navController.addOnDestinationChangedListener(this)
}

override fun onDestinationChanged(
    controller: NavController,
    destination: NavDestination,
    arguments: Bundle?
) {
    if (destination.id in bottomNavDestinationIds) {
        appBarLayout.setExpanded(true, true)
    }
}}