理解Flutter中的路由管理

路由的理解

移動端,前端中的路由指的是頁面;例如:

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

flutter路由的關(guān)鍵對象

  • Navigator:路由管理器,就是用來實現(xiàn)頁面跳轉(zhuǎn)的
  • Route:頁面的抽象,定義了路由線路
  • Overlay:遮罩,Navigator的下層widget;Navigator包裹了Overlay;

flutter路由的實現(xiàn)分析

MaterialApp->WidgetsApp->Navigator
這是Navigator的widget層級包裹關(guān)系,也就是說Navigator在app啟動時就 已經(jīng)作為page(widegt)的上層;

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

注釋1 通過context獲取最上層的NavigatorState
注釋2 調(diào)用 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 調(diào)用_flushHistoryUpdates方法,主要刷新_RouteEntry狀態(tài)
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 調(diào)用_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:實現(xiàn)route對象 持有_navigator
5-2:初始化route對象的List<OverlayEntry> _overlayEntries 屬性(OverlayEntry持有創(chuàng)建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對象(持有新的路由對應(yīng)的widget)
6-2:包裝原有的OverlayEntry對象
6-3:OverlayState 的_entries清空了列表數(shù)據(jù),并把排序后的數(shù)據(jù)插入到列表;在原有的old列表 去除重復(fù)OverlayEntry對象
6-4:把在原有的old中的對象 插入到最后面
最后調(diào)用setState 重新build
重點

//Navigator 對應(yīng)的 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是一個有狀態(tài)的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

總結(jié)

  • 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;
  }```


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容