Flutter中頁面棧的管理-Navigator

Navigator ,在 Flutter 中 Navigator 是管理一組組件跳轉的核心組件。使用棧的方式對組件進行管理。不只是在咱們平常使用開發組件跳轉中並且在程序入口 App 中,一樣是使用 Navigator 對組件的初始化進行管理。bash

Navigator 棧中管理的不單單的是UI類型組件,並且能管理 Navigator 類型的。以下圖所示:動畫

Navigator 的構造方法以及其參數源碼以下:ui

///navigator.dart 749行 源碼以下

  /// Creates a widget that maintains a stack-based history of child widgets.
  ///
  /// The [onGenerateRoute] argument must not be null.
  const Navigator({
    Key key,
    this.initialRoute,
    @required this.onGenerateRoute,
    this.onUnknownRoute,
    this.observers = const <NavigatorObserver>[],
  }) : assert(onGenerateRoute != null),
       super(key: key);
複製代碼

其中有三個比較重要的構造參數,第一個是 initialRoute ,類型是 String ,是本 Navigetor 初始化跳轉的 Route 對應的 name。onGenerateRoute 是一個帶有傳入參數 RouteSettings 方法,每當使用當前 Navigator 根據 name 進行頁面處理(push、pop等等)都會先走到這個方法進行查找,找出對應的route,RouteSettings 中帶有 name、傳遞參數 arguments ,在方法中須要根據 initialRoute 返回對應的 Route 而且初始化一些須要用 name 進行跳轉的 Route。onUnknownRoute 是當使用 pushNamed() 進行跳轉新頁面沒法在 onGenerateRoute 返回對應的 Route 時,則跳轉 onUnknownRoute。this

使用例子:spa

Navigator(
      initialRoute: 'signup/personal_info',
      onGenerateRoute: (RouteSettings settings) {
        WidgetBuilder builder;
        switch (settings.name) {
          case 'signup/personal_info':
            builder = (BuildContext _) => CollectPersonalInfoPage();
            break;
          case 'signup/choose_credentials':
            builder = (BuildContext _) => ChooseCredentialsPage();
            break;
          default:
            throw Exception('Invalid route: ${settings.name}');
        }
        return MaterialPageRoute(builder: builder, settings: settings);
      },
    );
複製代碼

Navigator 是一個 StatefulWidget ,因此具體的功能都是在 NavigatorState 中實現的。code

例如,咱們跳轉到一個新組件有兩種寫法。cdn

一種是server

Navigator.of(context).pushNamed('signup/choose_credentials');

///Navigator.of(context) 
///navigator.dart 1449行 源碼以下:

  static NavigatorState of(
    BuildContext context, {
    bool rootNavigator = false,
    bool nullOk = false,
  }) {
    final NavigatorState navigator = rootNavigator
        ? context.rootAncestorStateOfType(const TypeMatcher<NavigatorState>())
        : context.ancestorStateOfType(const TypeMatcher<NavigatorState>());
    ...省略非關鍵代碼
    return navigator;
  }
複製代碼

能夠看出來 .of(contaxt) 方法返回的是 NavigatorState ,也就是說實際調用 .pushNamed() 的是 NavigatorState。在 .of() 方法中有個比較重要的參數是 rootNavigator,但咱們設置它爲 true 時,可以拿到入口 App 中的NavigatorState 進行操做。固然這裏的 App 中的 NavigatorState 並不能對全部的頁面都進行處理,如前面圖所示,假設 Navigator0 爲 App 的 NavigatorState ,它只能對 page一、page二、page三、page四、Navigator1 進行管理,同時, NavigatorState 並無提供一個獲取子 NavigatorState 的方法。blog

另外一種是開發

Navigator.pushNamed(context, routeName);

///navigator.dart 881行 源碼以下:

@optionalTypeArgs
  static Future<T> pushNamed<T extends Object>(
    BuildContext context,
    String routeName, {
    Object arguments,
   }) {
    return Navigator.of(context).pushNamed<T>(routeName, arguments: arguments);
  }
複製代碼

能夠看出這種跳轉的實際上是將第一種寫法封裝了下。

列舉一下經常使用的一些方法。

  • 打開新頁面而且根據條件關閉舊頁面。

邏輯:

A->B->C->D

在D中調用如下方法, Navigetor 根據歷史頁面重新到舊 D->C->B->A 依次調用第二個參數傳入的方法而且在方法中傳入對應的Route,若傳入方法返回 true 結束調用,打開新頁面。

Navigator.of(context).pushAndRemoveUntil(
            CupertinoPageRoute(builder: (con) => PageMain()), (route) {
          return false;
        });
Navigator.of(context).pushAndRemoveUntil(
            CupertinoPageRoute(builder: (con) => PageMain()),
            ModalRoute.withName("/"));
複製代碼
  • 關閉當前頁面並打開新頁面
//替換,不顯示關閉當前頁面的過程。
Navigator.of(context).pushReplacement(pageMainRoute);
//有關閉當前頁面的動畫過程。源碼中的實現方式是先pop在push。
Navigator.of(context).popAndPushNamed(routeName);
複製代碼
  • 根據條件從如今到開始依次關閉頁面
//倒序關閉直到route名爲「/」
Navigator.of(context).popUntil(ModalRoute.withName("/"));
//倒序關閉直到返回true
Navigator.of(context).popUntil((route) {
                                return false;
                              });
複製代碼
  • 打開新頁面,在新頁面關閉時返回值
//在新頁面關閉時會觸發 then ,返回值在方法的參數中。
Navigator.of(context)
              .pushNamed('signup/choose_credentials')
              .then((value) {
            print(value);
          });
//hello爲返回值
Navigator.of(context).pop("hello");
複製代碼
  • 替換頁面
//二者結果同樣,均可以用來替換棧中的歷史頁面
Navigator.of(context).replace(
                          oldRoute: Routes.pageLoginRoute,
                          newRoute: CupertinoPageRoute(
                              builder: (conx) => PageMain()));
Navigator.replaceRouteBelow(
                          context, anchorRoute: Routes.pageLoginRoute,
                          newRoute: Routes.pageLoginRoute);
複製代碼
  • 移除歷史頁面
//移除某個頁面
Navigator.of(context).removeRoute(Routes.pageLoginRoute);
//移除某個頁面以及以後的頁面
Navigator.of(context).removeRouteBelow(Routes.pageLoginRoute);
複製代碼
相關文章
相關標籤/搜索