一些问题
- 路由存在的意义?
- 如果是你,会如何设计?
- dialog、bottomsheet、snackbar、dropmenubutton的底层实现是怎样的?
- pop的时候路由是如何传递数据回到上一个界面的?
- hero动画如何实现?
基本定义
相关类
- Navigator:负责整个路由栈,在结构上实际是一个Overlay;
- NavigatorState:管理整个栈,通过_RouteEntry列表管理栈。有push、pop等操作;
- Overlay:完成页面的协调、展示;维护一个OveralyEntry列表;
- _Theatre:_Theatre用来管理所有页面,在_Theatre中,可见/不可见的子结点都会转换成Element,但是在绘制的时候,_Theatre对应的_RenderTheatre只会把可见的子结点绘制出来;Overlay中创建,onstage表示舞台,offstage表示观众席;
- OverlayEntry:用来在Overlay上展示Widget;
- RouteSettings:用来保存路由的名字和参数;
- Route:定义路由接口,保存RouteSettings;它的子类:
- OverlayRoute:页面元素的创建,展示Widget,createOverlayEntries创建两个OverlayEntry,用于构建视图;
- TransitionRoute:处理转场;
- ModalRoute:可以阻止与不同路由的交互;
- PopupRoute:
- RawDialogRoute:
- CupertinoDialogRoute:iOS风格的路由;
- RawDialogRoute:
- PageRoute:定义了路由构建及切换时转场动画的相关接口和属性;
- MaterialPageRoute:Material风格的路由,通过builder设置路由具体页面;
- CupertinoPageRoute:
- PageRouteBuilder:自定义转场动画;
- MaterialPageRoute:Material风格的路由,通过builder设置路由具体页面;
- PopupRoute:
- ModalRoute:可以阻止与不同路由的交互;
- TransitionRoute:处理转场;
- OverlayRoute:页面元素的创建,展示Widget,createOverlayEntries创建两个OverlayEntry,用于构建视图;
- _RouteEntry:包含Route,状态机管理,各个生命周期的回调处理,标记转场是否有动画效果,通过transitionDelegate属性配置;
- RouteTransitionRecord:_RouteEntry的父类;
- NavigatorObserver:监控push、pop、replace、remove路由的情况
- Page:继承于RouteSettings,自己创建Route,有一个key用来作为唯一性判断,用于设置Navigator的历史堆栈;
- MaterialPage:
- CupertinoPage:
- Router:精细化管理页面,路由信息提供器、解析器;
- RouteDelegate:定义路由行为,监听RouteInformationParser和应用状态,并构建Pages
- RouteInformation:
- RouteInformationParser:解析RouteInformation,它从RouteInformationProvider中获取RouteInformation,并将其解析为用户定义的数据类型;
- RouteInformationProvider:负责通知RouteInformation变化;
- RouterDelegate:定义了Router如何学习应用状态变化以及如何响应这些变化的应用特定行为。它的工作是监听RouteInformationParser和应用状态,并利用当前的Pages列表构建Navigator;
- BackButtonDispatcher:向Router报告返回按钮按下的情况;
路由状态
1 |
|
状态变化
add–>adding–>idle
NavigatorState初始化的时候,通过混入RestorationMixin,didChangeDependencies的时候调用restoreState校验是否有initialRoute,有则进行初始路由初始化,初始化状态为add;该方法最后调用_flushHistoryUpdates,接着调用entry.handleAdd,状态修改为adding,接着continue下一次循环,执行entry.didAdd。
push–>pushing–>idle
Navigator.push,将Route封装成_RouteEntry加入到_history中,并调用_flushHistoryUpdates。该方法返回Future对象,可用于接收返回结果。在_flushHistoryUpdates中调用entry.handlePush,状态切换为pushing;push/pushReplace有一个转场动画,动画结束后状态变为idle。
pop–>poping–>dispose–>disposed
Navigator.pop,如果entry的settings是Page,先让外部来判断是否需要pop,否则直接entry.pop,设置状态为pop,执行_flushHistoryUpdates,接着执行entry.handlePop,切换状态到popping,执行route.didPop,完成返回值的传递、移除动画启动。didPop中调用navigator.finalizeRoute方法,状态切换到dispose,刷新_flushHistoryUpdates,状态到disposed。
remove–>removing–>dispose–>disposed
Navigator.removeRoute,调用entry.remove,将当前状态设置为remove,并调用_flushHistoryUpdates。调用entry.handleRemoval切换状态到revoming,接着切换状态到dispose,并添加到toBeDisposed中,然后切换状态到disposed,整个过程不涉及动画。
命名路由
通过名字进行路由跳转,Navigator.pushNamed(context, ‘/xxx/yyy’);通过_WidgetsAppState中的_onGenerateRoute方法来根据名字返回不同的Route。
嵌套路由
showGeneralDialog
基本用法
1 | Future<T?> showGeneralDialog<T extends Object?>({ |
fluro分析
- 封装了原生代码,减少重复代码量;
- 封装了默认的转场动画;
- 所有路由组装成一个tree,统一管理所有路由,通过命名路由的方式跳转;
getx路由模块分析
- 记录了Navigator的key,方便其他地方获取NavigatorState;
- 封装Page,支持路由拦截,内置转场动画;