1. 导航栈核心概念与设计目标
导航栈是移动端页面跳转管理的基础模型。几乎所有主流移动平台(iOS UINavigationController、Android FragmentManager、Flutter Navigator)都基于栈结构设计。理解导航栈的核心原理,是自定义实现的基础。
1.1 栈结构与页面生命周期
导航栈遵循 后进先出(LIFO) 原则。栈底是根页面(首页),栈顶是当前可见页面。每当用户跳转页面,新页面被 push 到栈顶;点击返回时,栈顶页面被 pop 移除,前一个页面恢复可见。
栈操作直接触发页面的生命周期回调,典型周期序列如下:
| 操作 | 原栈顶页面 | 新页面 |
|---|---|---|
| push | 页面暂停(paused)或隐藏(hidden) | 页面创建并显示(created → active) |
| pop | 页面销毁(destroyed) | 前一个页面恢复(resumed) |
| replace | 页面销毁 | 新页面创建并显示 |
1.2 导航控制器的核心职责
导航控制器(NavigationController)是栈的管理者,需承担如下职责:
- 栈数据模型管理:维护页面实例列表,支持 push、pop、peek 操作。
- 页面生命周期调度:在栈变化时,自动调用页面的生命周期方法(如 onAttach、onResume、onPause、onDetach)。
- 转场动画协调:在 push/pop 时驱动入场/出场动画,确保视觉过渡平滑。
- 状态保存与恢复:在应用被系统回收时,保存栈中每个页面的状态;重建后恢复栈结构。
- 手势交互支持:提供滑动返回、边缘手势等交互能力。
常见设计误区:将导航控制器与业务逻辑耦合,或在栈中存储页面实例以外的全局数据。控制器应仅管理页面对象和状态,不直接操作业务数据。
1.3 常见应用场景对比
| 场景 | 栈结构 | 核心挑战 |
|---|---|---|
| 单页列表→详情 | 主页 + 详情页(2层) | 返回后保持列表滚动位置 |
| 多级表单填写 | 表单页1 → 表单页2 → 表单页3 | 逐层返回时数据同步 |
| 登录/注册流程 | 登录页 → 注册页 → 主页 | 登录后清空中间栈 |
| 分步向导(Wizard) | 向导页1 → 向导页2 → 向导页3 | 步骤跳转与回退控制 |
| 嵌套栈(Tab + 导航) | TabA的主栈 + TabB的主栈 | 子栈独立管理,Tab切换时冻结/恢复 |
1.4 导航栈数据模型设计
一个可运行的导航栈,其核心数据模型至少包含如下结构:
class NavigationStack {
private List<PageEntry> stack = new ArrayList<>();
PageEntry peek() {
if (stack.isEmpty()) return null;
return stack.get(stack.size() - 1);
}
void push(PageEntry entry) {
// 旧栈顶生命周期 → paused
if (!stack.isEmpty()) peek().onPause();
// 新页面入栈
stack.add(entry);
entry.onCreate();
entry.onResume();
}
PageEntry pop() {
if (stack.isEmpty()) throw new IllegalStateException("stack empty");
PageEntry top = stack.remove(stack.size() - 1);
top.onDestroy();
// 新栈顶恢复
if (!stack.isEmpty()) peek().onResume();
return top;
}
}
设计要点:
PageEntry 应包含页面实例、标识符、动画配置、额外状态数据。栈结构应支持遍历(用于状态保存),也要支持快速获取栈顶。
1.5 导航栈核心工作流(SVG)
下图展示了一个三页面入栈到出栈的完整生命周期流转:
注意:上图中“首页”入栈后为 active,当“详情页”入栈时首页自动变为 paused;“详情页”再入栈“设置页”后,“详情页”同样变为 paused。当“设置页”pop 后,“详情页”恢复 active,而首页仍保持 paused。这是典型的多页面栈状态管理模型。