FlutteNavigator入坑手册
Navigator简介
导航,负责管理页面之间的切换,通过内置的栈来保存各个页面的信息,App启动时,MaterialApp会自动创建一个Navigator,它的根视图就是我们配置的MaterialApp对应的Home页面。
Navigator主要功能介绍

Navigator流程简介

多个Navigator管理方案

NavigatorState
Navigator是有状态的,NavigatorState对应导航的状态,是执行页面出战入栈的具体实例,每个Navigator内部创建一个NavigatorState时候,会将当前的state保存在GlobalKey中,它通过Element缓存了当前的state.
RouteFactory
它是一个工厂函数,根据指定的路由配置信息生成一个PageRoute(路由),使用Navigator的Context来创建Widget
RouteBuilder
它和RouteFactory类似,多了一个BuildContext参数,可以通过指定的Context来初始化PageRoute
RouteListFactory
它也是一个构造PageRoute的方法,只不过返回的是一个数组,NavigatorState在初始化时候在onGenerateInitialRoutes方法创建。
RoutePredicate
它是一个检查路由配置信息的函数,用于确认某两个路由是否为相同
WillPopCallback
它是对系统默认返回按钮事件拦截的回掉,用于对当前NavigatorState状态确认,是否在栈底,再根据业务逻辑选择返回或是不返回
PopPageCallback
用于删除Pop的页面在Navigator内的配置信息(page).
RoutePopDisposition
一个枚举值,用于指定当前需要pop的路由当前在NavigatorState中的状态,便于对路由进行行为更加精确管理。 包含3个值pop,doNotPop,bubble(pop事件移交给系统导航,通常关闭app),因为pop时需要做前置检查,所以每次pop时都会检查当前Route.willPop的拦截方法是否做了其他的处理。
Route
在Navigator和页面切换之间定义了一层抽象的接口(入栈,出栈),它包含了页面的构建信息Builder构造方法,同时也提供了一个List<OverlayEntry>,页面切换过程中的可视化界面是由很多个OverlayEntry实现的,Navigator内部由一个容器Overlay,在切换页面时不同的时刻插入对应状态的OverlayEntry,最终呈现出切换页面的过程,它内部还持有了当前的NavigatorState.
RouteSettings
提供Route的设置信息,如当前的路有的名字,以及传递给页面的参数,名字不可以参略,但一般建议加上,这对于我们定义问题,以及路由检查非常重要。
Functions
-
RouteFactory
Route创建的工厂函数
-
RouteBuilder
Route创建工厂函数,带BuildContext
-
RouteListFactory
- 批量创建
Route
- 批量创建
-
RoutePredicate
-
WillPopCallback
-
PopPageCallback
-
RoutePopDisposition
index value des pop 0 允许返回 doNotPop 1 不允许返回 bubble 2 返回事件交给系统返回按钮 -
Route
-
Route: 构造方法,包含一个
RouteSettings,配置路有的名字和传递参数 -
navigator: 管理导航的焦点事件
-
_updateSettings: 更新路有的配置信息,会触发
OverlayEntries的重新创建 -
overlayEntries: 路由的遮盖物对象,在切换路由时提供可视化的界面给导航
-
install: 装配初始化该路有的配置信息,当
Route被插入到Navigator中的时候调用,创建具体的overlayEntries(遮盖物)对象,它提供给Navigator的Overlay(rootWidget)构建导航的当前视图。 -
didPush:
Route加入到Navigator之后调用,返回一个TickerFuture对象,当ticker完成才获得导航的焦点事件,这个方法使用于带有转场的push回调,如果路有是直接出现在屏幕不带任何转场效过,则将会调用didAdd方法来替代它。 -
didReplace: 当路有在
Navigator中替换后调用 -
willPop: 内部判定当前路由执行pop方法时的pop状态,安全检测
-
willHandlePopInternally: 是否在内部自动处理pop
-
currentResult: 一个默认的缺省值,用于存储当前路由pop时的返回值(只有当poped没有返回值时才会用它)
-
popped: 当前路有从
Navigator中移除时的future,可以通过它来监听返回的数据 -
_popCompleter: 内部私有的变量,用于记录和管理pop的future.
-
didPop: 用于向当前
Route提交一个pop请求,如果返回为true,这个Route将会从导航中移除。 -
didComplete: 由
didPop请求触发,这个方法在pop动画开始之前结束 -
didPopNext: 拦截已经从
Navigator移除的Route,当前的Route已经成功添加 -
didChangeNext: 新的
Route已经添加到Navigator的回调 -
didChangePrevious: didPush/didReplace执行成功之后
-
changedInternalState: 当route内部状态发生改变时调用,
willHandlePopInternally,didPop,Offstage触发 -
changedExternalState:
NavigatorState执行rebuild时触发 -
dispose: 释放navigator,当
Route从NavigatorState中移除之后把Route所持有的navigator至为null. -
isCurrent: 栈顶
-
isFirst: 栈底
-
isActive: 当前可见的route,通常在栈顶,如果有透明的
route,它之上,它也会保持active状态,但是不会渲染,由ModalRoute.maintainState保持它的状态
-
-
RouteSettings:
- 包含两个参数
name,arguments,分别对应route的名字和传给路由的参数
- 包含两个参数
-
Page: 继承于
RouteSettings,多了一个LocalKey,用于唯一性判定,因为导航允许中会有多个相同路由名字相同- createRoute: 根据
BuildContext创建一个路由,在NavigatorState内部创建
- createRoute: 根据
-
CustomBuilderPage
- CustomBuilderPage: 继承于
Page再次做了扩展,可以支持传入routeBuilder来创建一个新的Route
- CustomBuilderPage: 继承于
-
NavigatorObserver
- 导航路有管理的观察者,同场可以用来做埋点,数据分析
- _navigator
- didPush
- didPop
- didRemove
- didReplace
- didStartUserGesture
- didStopUserGesture
-
RouteTransitionRecord
-
Route转场记录,用于生成push和pop动画 -
route: 当前记录的
route -
isEntering:
route正在进入屏幕,如果标记为true -
markForPush: 在
TransitionDelegate.resolve的时候,如果isEntering为true,标记当前的Route将会采用push的方式进行转场. -
markForAdd: 标记这个
Route不需要转场就能添加到Navigator中,也是在TransitionDelegate.resolve方法中执行 -
markForPop: 带动画的pop,与
markForPush相反 -
markForComplete: 传入当前route的返回值,完成route并从当前导航移除,想比
markForPop,它不带动 -
markForRemove: 同
markForComplete不带返回结果
-
-
TransitionDelegate
- TransitionDelegate: 路由的转场代理,决定路由页面如何从进入屏幕和离开屏幕,以及他们对应的页面实体对象
page如何从Navigator.pages添加和移除。它只是一个抽象类,提供了一套api来决定路由的转场相关的命令,它的子类必须实现一个resolve的方法来指转场动画或是不使用转场动画
- TransitionDelegate: 路由的转场代理,决定路由页面如何从进入屏幕和离开屏幕,以及他们对应的页面实体对象
-
DefaultTransitionDelegate
- 对
TransitionDelegate的具体实现,通过resolve方法对newPageRouteHistory,locationToExitingPageRoute,pageRouteToPagelessRoutes重排,按顺序生成一个List<RouteTransitionRecord>列表,并标记route不同的转场方式.
- 对
-
Navigator
-
Navigator: 采用堆栈的规则管理导航容器窗口中的页面插入和移除操作,是由一个Overlay的Widget管理的,可以把它理解成为当前导航的可视化的窗口,基于Overaly添加和删除子页面的
Widget.通过栈来管理Route,在Route插入和更新过程中会提供Overlay所需的OverlayEntries. -
pages: 记录当前的导航所持有的页面
-
onPopPage:
PopPageCallback,[Route.didPop]的callback的监听。 -
transitionDelegate: 控制路有的转场代理
-
initialRoute: 导航显示的第一个路由的名字
-
onGenerateRoute: 创建路有的工厂函数
-
onUnknownRoute: 创建未注册的路有
-
observers: 导航行为的观察者
-
defaultRouteName: 默认的初始化route名字,默认为
/ -
onGenerateInitialRoutes: 初始所有的路由
-
canPop
-
defaultGenerateInitialRoutes: 根据传入的
/routeName1/routeName2以斜杠分割,初始化多个路由
-
-
_RouteLifecycle
- 路由的生命周期状态管理
- staging: 等待转场代理决定该如何去执行这个路由
- add: 添加路由,通常在
onGenerateInitialRoutes和widget.pages初始化时创建,主要是在NavigatorState内部调用 - adding: 正在添加,准备好了转场
- push: 由push方法触发,功能和add方法相近,外部调用较多.
- pushReplace: 推送一个新的路有并替换当前路有
- pushing: 正在推送中,等待push完成
- replace: 直接替换当前路由
- idle: 导航处于等待状态
- pop: 退出一个页面,将会执行didPop
- remove: 移除一个页面,将会调用
didReplace/didRemove... - popping: 正在退出,等待执行
finalizeRoute去释放route - removing: 正在移除一个路由,等待路由动画完成,释放路由资源
- dispose: 立刻释放路由
-
disposed: 路由已经被完全释放
-
如下为
Navigator.dart对路由生命周期的定义,大致分为10个阶段// The _RouteLifecycle state machine (only goes down): //
// [creation of a _RouteEntry] phase1
// |
// +
// |\
// | \
// | staging。 phase2
// | /
// |/
// +-+----------+--+-------+
// / | | |
// / | | |
// / | | |
// / | | |
// / | | |
// pushReplace push* add* replace* phase3
// \ | | |
// \ | | /
// +--pushing# adding / phase4(animate阶段,非必选)
// \ / /
// \ / /
// idle--+-----+ phase5
// / \
// / \
// pop* remove* phase6
// / \
// / removing# phase7(animate阶段,非必选)
// popping# |
// | |
// [finalizeRoute] | phase8
// \ |
// dispose* phase9
// |
// |
// disposed phase10
// |
// |
// [_RouteEntry garbage collected]
// (terminal state) -
_RouteEntryPredicate: 检查是否为同一个路由
-
_RouteEntry
- 继承于
RouteTransitionRecord - route: Route
- currentState: _RouteLifecycle
- lastAnnouncedPreviousRoute: Route.didChangePrevious参数
- lastAnnouncedPoppedNextRoute: Route.didPopNext参数
- lastAnnouncedNextRoute: Route.didChangeNext参数
- hasPage:
route.settings is Page;,route settings参数是否为Page类型 - canUpdateFrom: 当前route为page,且大于phase5(idle.index)
- handleAdd: 执行
route.install创建overlayEntries,并将状态设置为adding - handlePush: 处理
push和pushReplace,生成routeFuture并等待动画完成,如果是replace方法这直接替换 - handleDidPopNext: pop下一个route
- handlePop: 处理pop事件,执行NavigatorObserver的
didPop方法,将其状态设置为popping,pop动画是由delegate自动执行的 - handleRemoval: remove -> removing - > observer(didRemove)
- doingPop: pop标志
- didAdd: adding -> idle -> observer(didPush)
- pop: doingPop = true -> pop -> doingPop = false;
- remove: 设置当前祖航太为remove状态
- complete: 页面退出时返回结果回调用,完成后设置为
remove状态 - finalize: 标记为销毁状态
- dispose: 将路由释放
- willBePresent:将要被展示 [add, idle]
- isPresent: 展示中[add, remove]
- suitableForAnnouncement: [push, removing]
- suitableForTransitionAnimation: [push, removing]
- shouldAnnounceChangeToNext
- isPresentPredicate:
entry.isPresent - suitableForTransitionAnimationPredicate:
entry.suitableForTransitionAnimation - willBePresentPredicate:
entry.willBePresent - isRoutePredicate:
entry.route == route - isEntering:
currentState == _RouteLifecycle.staging; - markForPush:
currentState = _RouteLifecycle.push - markForAdd:
currentState = _RouteLifecycle.add; - markForPop:
pop<dynamic>(result); - markForComplete:
complete<dynamic>(result); - markForRemove:
currentState = _RouteLifecycle.remove;
- 继承于
-
NavigatorState
- 当前
Navigator的State - _overlayKey:
GlobalKey保存窗口的Element - _history: 记录
_RouteEntry,提供转场动画过程页面的配置信息(widget) - focusScopeNode: 提供焦点范围
- _debugLocked: 避免重复的入栈出栈操作
- _debugCheckDuplicatedPageKeys
- initState
void initState() { ... //关联observers
for (final NavigatorObserver observer in widget.observers){ ...
if (widget.pages.isNotEmpty) { ... 添加初始化的`pages`
_history.addAll(
widget.pages.map((Page<dynamic> page) => _RouteEntry(
page.createRoute(context),
initialState: _RouteLifecycle.add, //初始化直接添加不需要动画
))
);
} else { ... 初始化default route
initialRoute = initialRoute ?? Navigator.defaultRouteName;
if (initialRoute != null) { ... 添加外部传入的`intialRoute`
_history.addAll(widget.onGenerateInitialRoutes(
_RouteEntry(route, initialState: _RouteLifecycle.add,
...
_flushHistoryUpdates(); //更新`history`中route处于非`disposed`和`staging`状态的route,更新`overlayEntries`,删除或移至`overlay`中更新界面
...- didUpdateWidget:
void didUpdateWidget(Navigator oldWidget) { ... if (oldWidget.observers != widget.observers) { ... //更新Observers
if (oldWidget.pages != widget.pages) { ... //更新pages
_updatePages();
for (final _RouteEntry entry in _history)
entry.route.changedExternalState(); //更新route外部状态
```
- dispose:
```dart
void dispose() { ...
for (final NavigatorObserver observer in widget.observers)
observer._navigator = null;
focusScopeNode.dispose();
for (final _RouteEntry entry in _history)
entry.dispose();
super.dispose(); ...
}- overlay:
_overlayKey.currentState; - _allRouteOverlayEntries:
_history->yield* entry.route.overlayEntries;,获取所有的overlayEntries - _lastAnnouncedRouteName: 用于传递给Native,是上次的
lastEntry?.route?.settings?.name;routeName - _debugUpdatingPage: debug标志未
- _updatePages: 更新pages的层级,确保page和history的层级对应
- _flushHistoryUpdates: 检查
history中routeEntry的LifeCycle并执行RouteEntry相关的方法,执行具体的导航操作,它是具体的执行者.而Navigator则倾向于管理RouteEntry栈,和提供窗口容器。 - _flushRouteAnnouncement: 同步更新路由状态,用于传递给native
- _getRouteBefore:
previousRoute - _getIndexBefore:
- _getRouteAfter:
next RouteEntry - _routeNamed: 根据route name获取一个新的
Route - _afterNavigation: 统计导航信息,debug用
- canPop: 检查栈中是否还存在页面,至少有2个,以及是否由系统处理返回键(android back 按钮)
- maybePop: 最后一个路由执行出栈操作
- popUntil: 依次执行pop操作,直到指定的route
- removeRoute: 立刻移除某个route
- removeRouteBelow: 替换某个路由下面的route
- finalizeRoute: 结束路由生命周期,如果正在pop则同步完成
- 当前
Route子类
Route (navigator.dart)
OverlayRoute (routes.dart)
TransitionRoute (routes.dart)
ModalRoute (routes.dart)
PageRoute (pages.dart)
CupertinoPageRoute (route.dart)
MaterialPageRoute (page.dart)
_SearchPageRoute (search.dart)
PageRouteBuilder (pages.dart)
PopupRoute (routes.dart)
_CupertinoModalPopupRoute (route.dart)
_ContextMenuRoute (context_menu.dart)
_ModalBottomSheetRoute (bottom_sheet.dart)
_DropdownRoute (dropdown.dart)
_PopupMenuRoute (popup_menu.dart)
_DialogRoute (routes.dart)
LocalHistoryRoute (routes.dart)
ModalRoute (routes.dart)
PageRoute (pages.dart)
CupertinoPageRoute (route.dart)
MaterialPageRoute (page.dart)
_SearchPageRoute (search.dart)
PageRouteBuilder (pages.dart)
PopupRoute (routes.dart)
_CupertinoModalPopupRoute (route.dart)
_ContextMenuRoute (context_menu.dart)
_ModalBottomSheetRoute (bottom_sheet.dart)
_DropdownRoute (dropdown.dart)
_PopupMenuRoute (popup_menu.dart)
_DialogRoute (routes.dart)
RoutePageBuilder
构建不带动画的路由页面
RouteTransitionsBuilder
构建带动画的路由页面
路由信息记录
RouteTransitionRecord (navigator.dart)
_RouteEntry (navigator.dart)
导航维持了一个history列表,负责管理所有的`_RouteEntry`
页面的实体相关的类
OverlayEntry (overlay.dart)
WidgetBuilder builder; //builder生成的才是我们创建的页面
opaque(bool value)
_OverlayEntryWidget //提供TickMode的设置
- entry._key
- entry
DiagnosticableTree (diagnostics.dart)
Widget (framework.dart)
RenderObjectWidget (framework.dart)
MultiChildRenderObjectWidget (framework.dart)
_Theatre (overlay.dart) //管理overlayEntries层级,不活跃的页面设置为offstage
SchedulerBinding
- schedulerPhase
- persistentCallbacks //移除OverlayEntry时的buildePhase
小结
- Flutter导航的管理目前比较侧重于单个导航管理,对于传统的app需要切换bottom tab的路由管理方式支持不是很友好,如果不同tab切换并跳转, 需要附加很多额外的逻辑.
- 路由的添加和移除对动画也比较局限,比如enable/disable animate功能,也需要自定义去实现
- 对于Route有较多数据依赖的场景, 路由的替换操作也是不够友好的

浙公网安备 33010602011771号