Flutter 110: 頁面間小跳轉 (四)

      小菜計劃針對頁面間跳轉的路由相關知識做一個彙總,發現有兩類特殊方法暫未研究,今天特補充 Navigator 相關方法應用;

canPop

      小菜理解 Navigator 是對棧的操作,對於出棧的過程,可以通過 canPop 判斷棧內 Page 是否存在,防止在棧內沒有元素時強制 Pop 出棧引起異常;

源碼解析

bool canPop() {
    return _history.length > 1 || _history[0].willHandlePopInternally;
}

案例嘗試

if (Navigator.of(context).canPop()) {
  print('當前 ${ModalRoute.of(context).settings.name} 可以 Pop !');
  Navigator.pop(context);
} else {
  print('當前 Page 無法 Pop ! ModalRoute.of(context).isFirst = ${ModalRoute.of(context).isFirst}');
}

maybePop

      canPop 只是對棧內元素是否可以出棧的判斷,而 maybePop 不僅可以判斷還可以執行 Pop 出棧操作;

源碼解析

Future<bool> maybePop<T extends Object>([ T result ]) async {
  final _RouteEntry lastEntry = _history.lastWhere(_RouteEntry.isPresentPredicate, orElse: () => null);
  if (lastEntry == null)  return false;
  final RoutePopDisposition disposition = await lastEntry.route.willPop(); // this is asynchronous
  if (!mounted)
    return true; // forget about this pop, we were disposed in the meantime
  final _RouteEntry newLastEntry = _history.lastWhere(_RouteEntry.isPresentPredicate, orElse: () => null);
  if (lastEntry != newLastEntry)
    return true; // forget about this pop, something happened to our history in the meantime
  switch (disposition) {
    case RoutePopDisposition.bubble:
      return false;
    case RoutePopDisposition.pop:
      pop(result);
      return true;
    case RoutePopDisposition.doNotPop:
      return true;
  }
  return null;
}

      簡單分析源碼可得,maybePop 會有限判斷當前路由棧在列表中是否爲最後一個,如果是最後一個則不進行出棧操作,否則進行 Pop 出棧;小菜簡單理解爲 maybePop >= canPop + Pop

案例嘗試

// 分別在 PageA 和 PageB 頁面調用 maybePop
Navigator.of(context).maybePop();

MaterialApp

      我們每次新建一個工程,通常會採用 MaterialApp 作爲 runApp() 的始點,MaterialAppAndroid 風格的,若需要 iOS 風格的,則需要 CupertinoApp;即作爲整個應用風格 Widget;而 MaterialApp / CupertinoApp / WidgetApp 等小組件默認是內嵌 Navigator 的,小菜接下來介紹 MaterialApp 幾個重要屬性;

1. home

      當進入應用時,初始化展示的 Widget

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(primarySwatch: Colors.blue),
        initialRoute: '/',
        onGenerateRoute: generateRoute,
        home: Scaffold(
            appBar: AppBar(title: Text('HomePage')),
            body: Center(child: Text('HomePage'))));
  }
}

2. routes

      routes 爲靜態路由映射表,是 Map<String, WidgetBuilder> 類型,當使用類似於 pushNamed 靜態路由方式進行頁面跳轉時,其對應路由首先需要在此綁定;一般默認 / 對應 root 頁面,當然我們可以自定義爲其他名稱,只是系統規則一般是 /,其中 Navigator.defaultRouteName 對應的也是 /;其餘的頁面路由可以根據業務邏輯進行文件夾式的層級結構;小菜在 Android 原生開發時採用過 ARouter 插件,其方式基本類似;

      注意: 一般採用 home 方式展示 Widget 時,路由表中不設置 / 對應 root 路由;

3. initialRoute

      initialRoute 用於設置初始啓動頁面,一般設置後就無需設置 home 屬性,因爲 home 對應展示 Widget 優先級更高;若首頁映射表名稱採用 / 對應 root 路由時,可以省略 initialRoute 屬性;

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(primarySwatch: Colors.blue),
//        initialRoute: '/',
      routes: { '/': (context) => HomePage(title: 'HomePage') },
      onGenerateRoute: generateRoute,
//      home: Scaffold(
//          appBar: AppBar(title: Text('HomePage')),
//          body: Center(child: Text('HomePage'))),
    );
  }
}

4. onGenerateRoute

      onGenerateRouteRouteFactory 類型構造函數,當使用靜態路由進行頁面跳轉時,進入未在 routes 中綁定的頁面時,都會在 onGenerateRoute 中進行回調;一般在封裝時,不設置 routes 屬性,均在 onGenerateRoute 中進行業務判斷,常用作類似於攔截器的路由守衛等;同時對於公共的自定義路由專場動畫也可以再此處理;

Function generateRoute = (settings) {
  print('onGenerateRoute -> $settings');
  if (settings == null ||
      settings.name == null ||
      routes[settings.name] == null) {
    return MaterialPageRoute(builder: (context) => routes['/error']());
  } else if (settings.arguments != null) {
    return MaterialPageRoute(
        builder: (context) => routes[settings.name](settings.arguments));
  } else if (settings.name == '/') {
    return MaterialPageRoute(
        builder: (context) => routes[settings.name]('HomePage'));
  } else {
    return MaterialPageRoute(builder: (context) => routes[settings.name]());
  }
};

5. onUnknownRoute

      onUnknownRoute 同樣爲 RouteFactory 類型構造函數,當使用靜態路由進行頁面跳轉時,無法在 onGenerateRoute 中生成時進行回調;

6. builder

      builder 屬性常用作 MediaQuery 設備信息獲取或用戶信息偏好設置等;小菜之前有整理過關於 MediaQuery 的學習,再次不做贅述;


      對於頁面間的跳轉還有很多需要學習和探索的地方,小菜建議多讀源碼,多學習優秀三方庫的實現方式;如有錯誤,請多多指導!

來源: 阿策小和尚

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章