美文网首页
理解Flutter中的路由管理

理解Flutter中的路由管理

作者: only_run | 来源:发表于2020-06-17 20:46 被阅读0次

路由的理解

移动端,前端中的路由指的是页面;例如:

  • Android中activity,
  • IOS中的ViewController
  • Flutter 中的Route(页面的抽象)

flutter路由的关键对象

  • Navigator:路由管理器,就是用来实现页面跳转的
  • Route:页面的抽象,定义了路由线路
  • Overlay:遮罩,Navigator的下层widget;Navigator包裹了Overlay;

flutter路由的实现分析

MaterialApp->WidgetsApp->Navigator
这是Navigator的widget层级包裹关系,也就是说Navigator在app启动时就 已经作为page(widegt)的上层;

#路由跳转的方法
 Navigator.of(context)//1
.push(MaterialPageRoute(
      builder: (context)=>MyHomePage()
    ));//2

注释1 通过context获取最上层的NavigatorState
注释2 调用 NavigatorState的push方法

#NavigatorState
Future<T> push<T extends Object>(Route<T> route) {
  ...
    _history.add(_RouteEntry(route, initialState: _RouteLifecycle.push));//3
    _flushHistoryUpdates();//4
  ...
    _afterNavigation(route);
    return route.popped;
  }

注释3 对route对象做了一层包装,作为_RouteEntry对象,存放到_history列表
注释4 调用_flushHistoryUpdates方法,主要刷新_RouteEntry状态
overlay更新widget

 void _flushHistoryUpdates({bool rearrangeOverlay = true}) {
   ...
    int index = _history.length - 1;
    _RouteEntry next;
    _RouteEntry entry = _history[index];
    _RouteEntry previous = index > 0 ? _history[index - 1] : null;
    bool canRemoveOrAdd = false; // Whether there is a fully opaque route on top to silently remove or add route underneath.
    Route<dynamic> poppedRoute; // The route that should trigger didPopNext on the top active route.
    bool seenTopActiveRoute = false; // Whether we've seen the route that would get didPopNext.
    final List<_RouteEntry> toBeDisposed = <_RouteEntry>[];
    while (index >= 0) {
      switch (entry.currentState) {
        case _RouteLifecycle.add:
       ...
        case _RouteLifecycle.push:
        case _RouteLifecycle.pushReplace:
        case _RouteLifecycle.replace:
          assert(rearrangeOverlay);
          entry.handlePush(//注释5
            navigator: this,
            previous: previous?.route,
            previousPresent: _getRouteBefore(index - 1, _RouteEntry.isPresentPredicate)?.route,
            isNewFirst: next == null,
          );
          assert(entry.currentState != _RouteLifecycle.push);
          assert(entry.currentState != _RouteLifecycle.pushReplace);
          assert(entry.currentState != _RouteLifecycle.replace);
          if (entry.currentState == _RouteLifecycle.idle) {
            continue;
          }
          break;
       ...
      index -= 1;
      next = entry;
      entry = previous;
      previous = index > 0 ? _history[index - 1] : null;
    }
   ...
    if (rearrangeOverlay)//注释6
      overlay?.rearrange(_allRouteOverlayEntries);
  }

注释5 调用_RouteEntry的handlePush方法

void handlePush({ @required NavigatorState navigator, @required bool isNewFirst, @required Route<dynamic> previous, @required Route<dynamic> previousPresent }) {
  ...
    final _RouteLifecycle previousState = currentState;
    route._navigator = navigator;//5-1
    route.install();//5-2
    assert(route.overlayEntries.isNotEmpty);
    if (currentState == _RouteLifecycle.push || currentState == _RouteLifecycle.pushReplace) {
      final TickerFuture routeFuture = route.didPush();//5-3
      currentState = _RouteLifecycle.pushing;
      routeFuture.whenCompleteOrCancel(() {
        if (currentState == _RouteLifecycle.pushing) {
          currentState = _RouteLifecycle.idle;
          assert(!navigator._debugLocked);
          assert(() { navigator._debugLocked = true; return true; }());
          navigator._flushHistoryUpdates();
          assert(() { navigator._debugLocked = false; return true; }());
        }
      });
    } else {
      assert(currentState == _RouteLifecycle.replace);
      route.didReplace(previous);
      currentState = _RouteLifecycle.idle;
    }
   ...
  }

5-1:实现route对象 持有_navigator
5-2:初始化route对象的List<OverlayEntry> _overlayEntries 属性(OverlayEntry持有创建route对象时传入的widget)
5-3:返回一个Future对象 在完成push后 保障navigator获取焦点

接着看注释6,overlay是OverlayState的对象,_allRouteOverlayEntries是从_history中的_RouteEntry的Route对象的OverlayEntry对象 获取的

#OverlayState
void rearrange(Iterable<OverlayEntry> newEntries, { OverlayEntry below, OverlayEntry above }) {
    final List<OverlayEntry> newEntriesList = newEntries is List<OverlayEntry> ? newEntries : newEntries.toList(growable: false);//6-1
   ...
    if (newEntriesList.isEmpty)
      return;
    if (listEquals(_entries, newEntriesList))
      return;
    final LinkedHashSet<OverlayEntry> old = LinkedHashSet<OverlayEntry>.from(_entries);//6-2
    for (final OverlayEntry entry in newEntriesList) {
      entry._overlay ??= this;
    }
    setState(() {
      _entries.clear();//6-3
      _entries.addAll(newEntriesList);
      old.removeAll(newEntriesList);
      _entries.insertAll(_insertionIndex(below, above), old);//6-4
    });
  }

6-1:包装新的OverlayEntry对象(持有新的路由对应的widget)
6-2:包装原有的OverlayEntry对象
6-3:OverlayState 的_entries清空了列表数据,并把排序后的数据插入到列表;在原有的old列表 去除重复OverlayEntry对象
6-4:把在原有的old中的对象 插入到最后面
最后调用setState 重新build
重点

//Navigator 对应的 state
 @override
  Widget build(BuildContext context) {
    // This list is filled backwards and then reversed below before
    // it is added to the tree.
    final List<Widget> children = <Widget>[];
    bool onstage = true;
    int onstageCount = 0;
    for (int i = _entries.length - 1; i >= 0; i -= 1) {
      final OverlayEntry entry = _entries[i];
      if (onstage) {
        onstageCount += 1;
        children.add(_OverlayEntryWidget(
          key: entry._key,
          entry: entry,
        ));
        if (entry.opaque)
          onstage = false;
      } else if (entry.maintainState) {
        children.add(_OverlayEntryWidget(
          key: entry._key,
          entry: entry,
          tickerEnabled: false,
        ));
      }
    }
    return _Theatre(
      skipCount: children.length - onstageCount,
      children: children.reversed.toList(growable: false),
    );
  }

Overlay是一个有状态的widget,build的时候 把持有的全部OverlayEntry对象 包装成_OverlayEntryWidget,由_Theatre完成 渲染显示;

/// Special version of a [Stack], that doesn't layout and render the first
/// [skipCount] children.
///
/// The first [skipCount] children are considered "offstage".
class _Theatre extends MultiChildRenderObjectWidget {
...
}

_Theatre是一个特殊的widget,类似Stack;用来渲染指定范围的widget

总结

  • Navigator.of(context)实际返回的是NavigatorState;
  • pop,push等操作实际就是操作 List<_RouteEntry> _history = <_RouteEntry>[];
  • _RouteEntry是Route的包装类
  • Navigator组件 对overlay组件 做了一层包装,overlay控制页面的显示,
    通过持有_Theatre舞台组件,类似Stack指定哪些页面widget要显示
  Future<T> push<T extends Object>(Route<T> route) {
    assert(!_debugLocked);
    assert(() {
      _debugLocked = true;
      return true;
    }());
    assert(route != null);
    assert(route._navigator == null);
    _history.add(_RouteEntry(route, initialState: _RouteLifecycle.push));
    _flushHistoryUpdates();
    assert(() {
      _debugLocked = false;
      return true;
    }());
    _afterNavigation(route);
    return route.popped;
  }```


相关文章

网友评论

      本文标题:理解Flutter中的路由管理

      本文链接:https://www.haomeiwen.com/subject/vkylxktx.html