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 的学习,再次不做赘述;


      对于页面间的跳转还有很多需要学习和探索的地方,小菜建议多读源码,多学习优秀三方库的实现方式;如有错误,请多多指导!

来源: 阿策小和尚

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,165评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,503评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,295评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,589评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,439评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,342评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,749评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,397评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,700评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,740评论 2 313
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,523评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,364评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,755评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,024评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,297评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,721评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,918评论 2 336

推荐阅读更多精彩内容