简介

我们在flutter中可以使用Navigator.push或者Navigator.pushNamed方法来向Navigator中添加不同的页面,从而达到页面调整的目的。

一般情况下这样已经足够了,但是有时候我们有多个Navigator的情况下,上面的使用方式就不够用了。比如我们有一个主页面app的Navigator,然后里面有一个匹配好友的功能,这个功能有多个页面,因为匹配好友功能的多个页面实际上是一个完整的流程,所以这些页面需要被放在一个子Navigator中,并和主Navigator区分开。

那么应该如何处理呢?

搭建主Navigator

主Navigator是我们app的一些主要界面,这里我们有三个界面,分别是主home界面,一个setting配置界面和好友匹配界面。

其中好友匹配界面包含了三个子界面,这三个子界面将会用到子路由。

先来看下主路由,主路由的情况跟普通的路由没啥区别,这里我们首先定义和home和setting匹配的两个widget:HomePage和SettingsPage:

class HomePage extends StatelessWidget {
const HomePage({
super.key,
}); @override
Widget build(BuildContext context) {
return Scaffold(
appBar: _buildAppBar(context),
body: Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: const [
SizedBox(
width: 250,
height: 250,
child: Center(
child: Icon(
Icons.home,
size: 175,
color: Colors.blue,
),
),
),
SizedBox(height: 32),
Text(
'跳转到好友匹配页面',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
],
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.of(context).pushNamed(routeFriendMatch);
},
child: const Icon(Icons.add),
),
);
}

HomePage很简单,它包含了一个floatingActionButton,当点击它的时候会调用 Navigator.pushNamed方法进行路由切换。

然后是SettingsPage,它是一个简单的Column:

class SettingsPage extends StatelessWidget {
const SettingsPage({
super.key,
}); @override
Widget build(BuildContext context) {
return Scaffold(
appBar: _buildAppBar(),
body: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: List.generate(8, (index) {
return ListTile(
title: Text('设置项$index'),
);
}),
),
),
);
}

最后一个页面是FriendMatchFlow,这个页面比较复杂,我们在下一个再进行讲解。

然后我们为主路由在onGenerateRoute方法中进行定义:

void main() {
runApp(
MaterialApp(
onGenerateRoute: (settings) {
late Widget page;
if (settings.name == routeHome) {
page = const HomePage();
} else if (settings.name == routeSettings) {
page = const SettingsPage();
} else if (settings.name == routeFriendMatch) {
page = const FriendMatchFlow(
setupPageRoute: routeFriendMatchPage,
);
} return MaterialPageRoute<dynamic>(
builder: (context) {
return page;
},
settings: settings,
);
},
debugShowCheckedModeBanner: false,
),
);
}

主路由很简单,跟普通的路由没有太多的区别。

构建子路由

接下来是构建子路由的步骤。在主路由中,如果路由的名称是routeFriendMatch,那么就会跳转到FriendMatchFlow。

而这个flow页面实际上是由几个子页面组成的:选择好友页面,等待页面,匹配页面和匹配完毕页面。

具体的页面代码这里就不写了,我们主要来讲一下子路由的使用。

对于FriendMatchFlow来说,它本身是一个Navigator,所以我们的build方法是这样的:

  Widget build(BuildContext context) {
return WillPopScope(
onWillPop: _isExitDesired,
child: Scaffold(
appBar: _buildFlowAppBar(),
body: Navigator(
key: _navigatorKey,
initialRoute: widget.setupPageRoute,
onGenerateRoute: _onGenerateRoute,
),
),
);
}

因为他需要根据用户的不同点击来进行内部路由的切换,所以需要保存对当前子Navigator的应用,所以这里FriendMatchFlow是一个StatefulWidget,并且上面的_navigatorKey是一个GlobalKey对象,以提供对子Navigator的引用:

  final _navigatorKey = GlobalKey<NavigatorState>();

这里的_onGenerateRoute方法,跟主路由也是很类似的,主要定义的是子路由中页面的跳转:

  Route _onGenerateRoute(RouteSettings settings) {
late Widget page;
switch (settings.name) {
case routeFriendMatchPage:
page = WaitingPage(
message: '匹配附近的好友...',
onWaitComplete: _onDiscoveryComplete,
);
break;
case routeFriendSelectPage:
page = SelectFriendPage(
onFriendSelected: _onFriendSelected,
);
break;
case routeFriendConnectingPage:
page = WaitingPage(
message: '匹配中...',
onWaitComplete: _onConnectionEstablished,
);
break;
case routeFriendFinishedPage:
page = FinishedPage(
onFinishPressed: _exitSetup,
);
break;
}

这里的on***Selected是VoidCallback回调,用来进行路由的切换:

  void _onDiscoveryComplete() {
_navigatorKey.currentState!.pushNamed(routeFriendSelectPage);
} void _onFriendSelected(String deviceId) {
_navigatorKey.currentState!.pushNamed(routeFriendConnectingPage);
} void _onConnectionEstablished() {
_navigatorKey.currentState!.pushNamed(routeFriendFinishedPage);
}

可以看到上面的路由切换实际上是在子路由上切换,跟父路由无关。

如果想要直接从子路由跳出到父路由该怎么处理呢?很简单,调用Navigator.of的pop方法即可:

  void _exitSetup() {
Navigator.of(context).pop();
}

这里的context默认是全局的context,所以会导致主路由的跳转变化。

总结

以上的代码运行结果如下:

虽然上面的例子看起来复杂,但是大家只要记住了不同的路由使用不同的Navigator范围进行跳转就行了。

本文的例子:https://github.com/ddean2009/learn-flutter.git

flutter系列之:创建一个内嵌的navigation的更多相关文章

  1. 补习系列(17)-springboot mongodb 内嵌数据库

    目录 简介 一.使用 flapdoodle.embed.mongo A. 引入依赖 B. 准备测试类 C. 完善配置 D. 启动测试 细节 二.使用Fongo A. 引入框架 B. 准备测试类 C.业 ...

  2. 补习系列(17)-springboot mongodb 内嵌数据库【华为云技术分享】

    目录 简介 一.使用 flapdoodle.embed.mongo A. 引入依赖 B. 准备测试类 C. 完善配置 D. 启动测试 细节 二.使用Fongo A. 引入框架 B. 准备测试类 C.业 ...

  3. Linux内核系列—C语言中内嵌汇编 asm __volatile__,asm__volatile_【转】

    转自:http://www.bkjia.com/Androidjc/1109412.html 在内嵌汇编中,可以将C语言表达式指定为汇编指令的操作数,而且不用去管如何将C语言表达式的值读入哪个寄存器, ...

  4. 【Azure 机器人】微软Azure Bot 编辑器系列(1) : 创建一个天气对话机器人(The Bot Framework Composer tutorials)

    欢迎来到微软机器人编辑器使用教程,从这里开始,创建一个简单的机器人. 在该系列文章中,每一篇都将通过添加更多的功能来构建机器人.当完成教程中的全部内容后,你将成功的创建一个天气机器人(Weather ...

  5. ADF_General JSF系列1_创建一个简单的JSF Application

    2015-02-17 Creatd By BaoXinjian

  6. NPOI-Excel系列-1000.创建一个标准的Excel文件

    using NPOI.HSSF.UserModel; using Microsoft.VisualStudio.TestTools.UnitTesting; using System.IO; name ...

  7. Cordova 系列之创建一个iOS项目

    1.打开终端 2.输入命令 $ cd Desktop (PS:Desktop表示放在桌面,你可以选择放任意位置) 3.$  cordova create HelloWorld com.example. ...

  8. strapi系列-如何创建一个定时任务-Cron Jobs

    Cron 是什么? Cron 有多种用途. Cron Jobs 用于安排服务器上的任务运行.它们最常用于自动化系统管理或维护.然而,它们也与 Web 应用程序的构建相关. Web 应用程序可能需要在各 ...

  9. (二)JavaMail创建包含内嵌图片的邮件

    链接:https://blog.csdn.net/qq_41151659/article/details/96475739 代码如下: import com.sun.mail.util.MailSSL ...

  10. 二十二、SAP中创建一个内表,并添加内容循环输出显示

    一.直接上代码 二.输出如下

随机推荐

  1. UnityAndroid 获取根目录文件

    1. 在Unity打包时获取SD权限 2. Android根目录为 "/storage/emulated/0"; 代码: if (Directory.Exists("/s ...

  2. jquery的网络引用地址

    http://apps.bdimg.com/libs/jquery/1.6.4/jquery.js http://apps.bdimg.com/libs/jquery/1.6.4/jquery.min ...

  3. 解决windows的mysql无法启动 服务没有报告任何错误的经验。

    解决windows的mysql无法启动 服务没有报告任何错误的经验. 相信很多人都遇到过安装Mysql的时候出现各种各样的问题,教大家解决window下mysql服务没有报告任何错误的情况下无法启动 ...

  4. nacos之服务注册、发现及维持心跳

    注册服务(增加健康检查)  服务发现(默认15s没有心跳请求,则自动注销服务)  心跳(维持服务运行状态) 参数说明 serviceName:服务名称 beat:服务的详细信息 ip 端口等,json ...

  5. 合并B站video.m4s和audio.m4s

    ffmpeg -i D:\a\video.m4s -i D:\a\audio.m4s -codec copy D:\a\a.mp4

  6. 第一课 Markdown 实操

    1.Markdown (#加空格) 二级标题 (##加空格) 三级标题 (###加空格) 四级标题 (####加空格) 2.字体 Hello world 加粗(字体2边加**) Hello world ...

  7. Linux 使用Samba或NFS实现文件共享

    SAMBA文件共享服务 Samba是一款开源的文件共享软件,经过简单配置就能够实现Linux系统与Windows系统之间的文件共享工作. 例1:配置Samba服务前,先删掉Samba服务主配置文件中的 ...

  8. JS缓存三种方法_sessionStorage_localStorage_Cookie

    1.sessionStorage:临时的会话存储 只要当前的会话窗口未关闭,存储的信息就不会丢失,即便刷新了页面,或者在编辑器中更改了代码,存储的会话信息也不会丢失. 2.localStorage:永 ...

  9. 2020年第11届蓝桥杯C/C++B组 第二轮省赛

    # JJU-干干 试题A :门牌制作[问题描述]小蓝要为一条街的住户制作门牌号.这条街一共有 2020 位住户,门牌号从 1 到 2020 编号.小蓝制作门牌的方法是先制作 0 到 9 这几个数字字符 ...

  10. 动手搭建ssm框架

    现在很多公司用的开源框架很多都是ssm框架的一个结构,这里我自己试着自己搭一个简单的框架,大家共同学习.下面一起跟着我搭建吧,本人菜鸟,有任何不对的地方有望指出. 框架结构:spring(4.3.9. ...