zoukankan      html  css  js  c++  java
  • FlutteNavigator入坑手册

    Navigator简介

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

    Navigator主要功能介绍

    Navigator流程简介

     

    多个Navigator管理方案

    NavigatorState

    Navigator是有状态的,NavigatorState对应导航的状态,是执行页面出战入栈的具体实例,每个Navigator内部创建一个NavigatorState时候,会将当前的state保存在GlobalKey中,它通过Element缓存了当前的state.

    RouteFactory

    它是一个工厂函数,根据指定的路由配置信息生成一个PageRoute(路由),使用NavigatorContext来创建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

    1. RouteFactory

      • Route创建的工厂函数
    2. RouteBuilder

      • Route创建工厂函数,带BuildContext
    3. RouteListFactory

      • 批量创建Route
    4. RoutePredicate

    5. WillPopCallback

    6. PopPageCallback

    7. RoutePopDisposition

      indexvaluedes
      pop 0 允许返回
      doNotPop 1 不允许返回
      bubble 2 返回事件交给系统返回按钮
    8. Route

      • Route: 构造方法,包含一个RouteSettings,配置路有的名字和传递参数

      • navigator: 管理导航的焦点事件

      • _updateSettings: 更新路有的配置信息,会触发OverlayEntries的重新创建

      • overlayEntries: 路由的遮盖物对象,在切换路由时提供可视化的界面给导航

      • install: 装配初始化该路有的配置信息,当Route被插入到Navigator中的时候调用,创建具体的overlayEntries(遮盖物)对象,它提供给NavigatorOverlay(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,当RouteNavigatorState中移除之后把Route所持有的navigator至为null.

      • isCurrent: 栈顶

      • isFirst: 栈底

      • isActive: 当前可见的route,通常在栈顶,如果有透明的route,它之上,它也会保持active状态,但是不会渲染,由ModalRoute.maintainState保持它的状态

    9. RouteSettings:

      • 包含两个参数name,arguments,分别对应route的名字和传给路由的参数
    10. Page: 继承于RouteSettings,多了一个LocalKey,用于唯一性判定,因为导航允许中会有多个相同路由名字相同

      • createRoute: 根据BuildContext创建一个路由,在NavigatorState内部创建
    11. CustomBuilderPage

      • CustomBuilderPage: 继承于Page再次做了扩展,可以支持传入routeBuilder来创建一个新的Route
    12. NavigatorObserver

      • 导航路有管理的观察者,同场可以用来做埋点,数据分析
      • _navigator
      • didPush
      • didPop
      • didRemove
      • didReplace
      • didStartUserGesture
      • didStopUserGesture
    13. RouteTransitionRecord

      • Route转场记录,用于生成pushpop动画

      • route: 当前记录的route

      • isEntering: route正在进入屏幕,如果标记为true

      • markForPush: 在TransitionDelegate.resolve的时候,如果isEnteringtrue,标记当前的Route将会采用push的方式进行转场.

      • markForAdd: 标记这个Route不需要转场就能添加到Navigator中,也是在TransitionDelegate.resolve方法中执行

      • markForPop: 带动画的pop,与markForPush相反

      • markForComplete: 传入当前route的返回值,完成route并从当前导航移除,想比markForPop,它不带动

      • markForRemove: 同markForComplete不带返回结果

    14. TransitionDelegate

      • TransitionDelegate: 路由的转场代理,决定路由页面如何从进入屏幕和离开屏幕,以及他们对应的页面实体对象page如何从Navigator.pages添加和移除。它只是一个抽象类,提供了一套api来决定路由的转场相关的命令,它的子类必须实现一个resolve的方法来指转场动画或是不使用转场动画
    15. DefaultTransitionDelegate

      • TransitionDelegate的具体实现,通过resolve方法对newPageRouteHistory,locationToExitingPageRoute,pageRouteToPagelessRoutes重排,按顺序生成一个List<RouteTransitionRecord>列表,并标记route不同的转场方式.
    16. 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以斜杠分割,初始化多个路由

    17. _RouteLifecycle

      • 路由的生命周期状态管理
      • staging: 等待转场代理决定该如何去执行这个路由
      • add: 添加路由,通常在onGenerateInitialRouteswidget.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: 检查是否为同一个路由

    18. _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: 处理pushpushReplace,生成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;
    19. NavigatorState

      • 当前NavigatorState
      • _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: 检查historyrouteEntryLifeCycle并执行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有较多数据依赖的场景, 路由的替换操作也是不够友好的

  • 相关阅读:
    开发工具分享
    图形学杂记
    keyle的Shader-学习手札
    Keyle的3D数学-学习手札
    SuperStrange项目主页
    Unity3d基础知识(水文)
    和Keyle一起学ShaderForge – Custom Blinn-Phong
    和Keyle一起学ShaderForge – Create Base Shader
    和Keyle一起学ShaderForge
    和Keyle一起学StrangeIoc – 教程目录
  • 原文地址:https://www.cnblogs.com/wwoo/p/13783468.html
Copyright © 2011-2022 走看看