导航体系

Narrator Android · Jetpack Navigation · 导航图 / 层级 / 切换方式 / 回退栈策略

Narrator 全部页面跳转由 NavController 统一调度,导航配置集中在 res/navigation/nav_graph.xml。页面入口分为三类: 底部导航 侧边抽屉 子页面(navigate 入栈)

1. 导航图定义

文件res/navigation/nav_graph.xml 入口scriptFragment(剧本列表)

<navigation android:id="@+id/nav_graph" app:startDestination="@id/scriptFragment"> <!-- 16 个 <fragment> 节点,含 <argument> 与 <action> --> </navigation>

2. 导航层级

各 Fragment 的父子层级与跳转关系:

scriptFragment (剧本列表 — 底部导航 / 启动入口) │ ├── scriptDetailFragment (剧本详情) │ ├── outlineFragment (大纲编辑) │ ├── deductionFragment (演绎 / 三栏) │ ├── scriptCharactersFragment (角色管理) │ │ └── scriptCharacterEditFragment (剧本角色编辑) │ ├── scriptSettingsFragment (剧本设置) │ └── newChapterFragment (添加章节) │ ├── characterFragment (角色管理 — 底部导航) │ ├── characterEditFragment (角色详情编辑) │ └── scriptCharactersFragment (剧本角色管理) │ ├── aiFragment (AI 配置 — 底部导航) │ └── aiProviderDetailFragment (AI 服务商详情) │ ├── uiFragment (UI 主题 — 底部导航) ├── settingsFragment (设置 — 底部导航) ├── dialogueFragment (对话 — 抽屉) ├── manualFragment (手册 — 抽屉) └── trashFragment (回收站 — 抽屉)

3. 应用壳入口

3.1 MainActivity(主壳)

说明
文件MainActivity.java
布局res/layout/activity_main.xml
对应 Webweb/src/App.vue
组成标题栏 + NavHostFragment(内容区)+ BottomNavigationView + NavigationView(右侧抽屉)

3.2 底部导航栏(BottomNavigationView)

TabFragment菜单 ID图标
剧本ScriptFragmentnav_scriptic_script
角色CharacterFragmentnav_charactersic_characters
AIAiFragmentnav_aiic_ai
UIUiFragmentnav_uiic_ui
设置SettingsFragmentnav_settingsic_settings

3.3 侧边抽屉(NavigationView · 右侧)

菜单项Fragment菜单 ID
对话DialogueFragmentnav_dialogue
手册ManualFragmentnav_manual
回收站TrashFragmentnav_trash

4. 导航方式

方式触发实现
底部导航切换点击底部 TabBottomNavigationView.setOnItemSelectedListenerNavigationUI.onNavDestinationSelected(item, controller)
抽屉导航切换点击抽屉菜单项NavigationView.setNavigationItemSelectedListener → 关闭抽屉 + NavigationUI.onNavDestinationSelected
按钮点击导航页面内按钮BaseFragment.navigateTo(destId) / navigateToWithArgs(destId, args)
标题栏返回按钮点击 navController.popBackStack()(由 header_back_btn 统一处理)
系统返回键系统返回OnBackPressedCallback:抽屉打开先收起,否则 popBackStack()
标签默认app:defaultNavHost="true" 自动处理返回栈
🎯 标题栏按钮规则MainActivity.isSubPageDest()): 顶层页面显示 菜单按钮(点击打开抽屉); 子页面显示 返回按钮(点击 popBackStack())。 演绎页deductionFragment)特殊:同时显示返回按钮与 三圆点菜单。

5. 回退栈管理策略

所有顶层页面切换(底部 Tab / 抽屉菜单)统一使用以下 NavOptions

new NavOptions.Builder() .setLaunchSingleTop(true) .setPopUpTo(R.id.scriptFragment, false) .build()
选项含义
launchSingleTop(true)目标已在栈顶时不重复创建
popUpTo(scriptFragment, false)跳转前弹出 scriptFragment 之上的所有页面,但保留 scriptFragment 本身
💡 效果:反复切换底部 Tab 不会导致回退栈无限膨胀,按返回键始终回到首页(剧本列表)。 v3 修复了顶部 Tab 重复切换导致栈无限增长的问题。

5.1 NavController 初始化

为避免 Navigation.findNavController() 的时序问题,MainActivity 通过 FragmentManager 直接获取 NavHostFragment

getSupportFragmentManager().executePendingTransactions(); NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment); navController = navHostFragment.getNavController();

6. 动态主题配色

导航栏(顶部标题栏 / 底部 / 抽屉)在导航变化时由 MainActivity.applyDynamicThemeColors() 应用当前主题色:

7. 页面标题与可见性