【Flutter】路由与导航:复杂导航与深度链接
在开发大型 Flutter 应用时,复杂的导航管理是不可避免的。除了基本的页面跳转与返回操作外,很多应用会用到 嵌套路由、页面分组、TabBar 和 Drawer 的结合使用等复杂导航场景,甚至支持 深度链接 和 动态路由。本文将深入探讨这些高级导航技巧,并带你逐步实现它们。
实现嵌套路由与页面分组
Flutter 提供了灵活的导航机制,通过嵌套的 Navigator
可以实现多个层级的路由管理。在实际场景中,比如主页面中有多个模块(TabBar、底部导航栏等),每个模块内部又有子页面时,嵌套路由变得非常有用。
Navigator 嵌套实现
我们可以在主页面中定义一个 Navigator
,然后在每个模块的子页面中再定义一个 Navigator
来处理各自模块的内部页面导航。
示例
import 'package:flutter/material.dart';void main() {runApp(MyApp());
}class MyApp extends StatelessWidget { Widget build(BuildContext context) {return MaterialApp(home: MainPage(),);}
}class MainPage extends StatefulWidget { _MainPageState createState() => _MainPageState();
}class _MainPageState extends State<MainPage> {int _selectedIndex = 0;final List<Widget> _pages = [NestedNavigatorPage1(),NestedNavigatorPage2(),]; Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('Nested Navigator Example'),),body: _pages[_selectedIndex],bottomNavigationBar: BottomNavigationBar(currentIndex: _selectedIndex,onTap: (index) {setState(() {_selectedIndex = index;});},items: [BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Page 1'),BottomNavigationBarItem(icon: Icon(Icons.settings), label: 'Page 2'),],),);}
}// Page 1 with nested Navigator
class NestedNavigatorPage1 extends StatelessWidget { Widget build(BuildContext context) {return Navigator(onGenerateRoute: (settings) {return MaterialPageRoute(builder: (context) => Page1Main());},);}
}class Page1Main extends StatelessWidget { Widget build(BuildContext context) {return Scaffold(body: Center(child: ElevatedButton(child: Text('Go to Page 1.1'),onPressed: () {Navigator.push(context,MaterialPageRoute(builder: (context) => Page1Sub()),);},),),);}
}class Page1Sub extends StatelessWidget { Widget build(BuildContext context) {return Scaffold(body: Center(child: Text('Page 1.1'),),);}
}// Page 2 with nested Navigator
class NestedNavigatorPage2 extends StatelessWidget { Widget build(BuildContext context) {return Navigator(onGenerateRoute: (settings) {return MaterialPageRoute(builder: (context) => Page2Main());},);}
}class Page2Main extends StatelessWidget { Widget build(BuildContext context) {return Scaffold(body: Center(child: ElevatedButton(child: Text('Go to Page 2.1'),onPressed: () {Navigator.push(context,MaterialPageRoute(builder: (context) => Page2Sub()),);},),),);}
}class Page2Sub extends StatelessWidget { Widget build(BuildContext context) {return Scaffold(body: Center(child: Text('Page 2.1'),),);}
}
代码解析
- 嵌套的 Navigator:在
NestedNavigatorPage1
和NestedNavigatorPage2
中使用了各自的Navigator
,使得不同模块之间的导航彼此独立。 - 底部导航栏:通过
BottomNavigationBar
来切换模块,避免每次切换模块时都重置页面栈。
学习 TabBar 和 Drawer 结合导航
在很多应用中,常常会结合 TabBar 和 Drawer 来实现更复杂的导航布局。TabBar 用于页面的切换,而 Drawer 用于展示应用的全局导航菜单。
使用 TabBar 实现导航
TabBar 是用于在多个页面之间切换的组件,它通常与 TabController
一起使用。
import 'package:flutter/material.dart';void main() {runApp(MyApp());
}class MyApp extends StatelessWidget { Widget build(BuildContext context) {return MaterialApp(home: TabBarExample(),);}
}class TabBarExample extends StatelessWidget { Widget build(BuildContext context) {return DefaultTabController(length: 3,child: Scaffold(appBar: AppBar(title: Text('TabBar Example'),bottom: TabBar(tabs: [Tab(icon: Icon(Icons.home), text: 'Home'),Tab(icon: Icon(Icons.search), text: 'Search'),Tab(icon: Icon(Icons.settings), text: 'Settings'),],),),body: TabBarView(children: [Center(child: Text('Home Page')),Center(child: Text('Search Page')),Center(child: Text('Settings Page')),],),),);}
}
代码解析
DefaultTabController
:提供了TabController
的默认实现,用于管理选中的 Tab。TabBar
:定义了导航的 Tab 页。TabBarView
:用于展示对应的页面内容。
使用 Drawer 实现导航
Drawer
是一个侧边导航栏,通常用于提供全局的页面导航。
import 'package:flutter/material.dart';void main() {runApp(MyApp());
}class MyApp extends StatelessWidget { Widget build(BuildContext context) {return MaterialApp(home: DrawerExample(),);}
}class DrawerExample extends StatelessWidget { Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('Drawer Example'),),drawer: Drawer(child: ListView(padding: EdgeInsets.zero,children: <Widget>[DrawerHeader(child: Text('Menu'),decoration: BoxDecoration(color: Colors.blue,),),ListTile(title: Text('Page 1'),onTap: () {Navigator.push(context, MaterialPageRoute(builder: (context) => Page1()));},),ListTile(title: Text('Page 2'),onTap: () {Navigator.push(context, MaterialPageRoute(builder: (context) => Page2()));},),],),),body: Center(child: Text('Main Page')),);}
}class Page1 extends StatelessWidget { Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('Page 1'),),body: Center(child: Text('This is Page 1')),);}
}class Page2 extends StatelessWidget { Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('Page 2'),),body: Center(child: Text('This is Page 2')),);}
}
代码解析:
Drawer
:定义了一个侧边导航栏,提供了页面的跳转入口。ListTile
:在 Drawer 中使用ListTile
作为每个导航选项。
实现深度链接和动态路由
深度链接是指用户通过一个外部 URL 直接进入应用中的某个页面,而不是从主页面进入。Flutter 支持将深度链接映射到应用的特定页面,并且还可以通过动态路由实现复杂的路由匹配。
动态路由
通过动态路由,应用可以根据传入的 URL 动态地匹配和展示页面。onGenerateRoute
是处理动态路由的核心方法。
import 'package:flutter/material.dart';void main() {runApp(MyApp());
}class MyApp extends StatelessWidget { Widget build(BuildContext context) {return MaterialApp(initialRoute: '/',onGenerateRoute: (RouteSettings settings) {if (settings.name == '/') {return MaterialPageRoute(builder: (context) => HomePage());} else if (settings.name == '/details') {final args = settings.arguments as String;return MaterialPageRoute(builder: (context) => DetailsPage(data: args));}return null;},);}
}class HomePage extends StatelessWidget { Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('Home Page'),),body: Center(child: ElevatedButton(child: Text('Go to Details'),onPressed: () {Navigator.pushNamed(context, '/details', arguments: 'Some data');},),),);}
}class DetailsPage extends StatelessWidget {final String data;DetailsPage({required this.data}); Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('Details Page'),),body: Center(child: Text('Passed data: $data'),),);}
}
代码解析
onGenerateRoute
:根据传入的 URL 动态生成页面,支持传递参数。- 深度链接:可以通过外部的 URL 链接直接跳转到应用中的某个页面。
总结
在本教程中,我们探讨了 Flutter 中更复杂的导航方式。通过 嵌套路由 和 页面分组,可以轻松管理多模块页面的导航逻辑;通过 TabBar 和 Drawer,实现了常见的导航布局;通过 动态路由 和 深度链接,支持外部 URL 链接直接跳转到特定页面。
- 嵌套路由:实现不同页面模块间的独立导航。
- TabBar 与 Drawer:结合导航,提供丰富的界面切换方式。
- 深度链接和动态路由:实现 URL 与页面的映射,增强用户体验。
掌握这些技巧后,你将能够开发出复杂的多页面应用,同时提供流畅的导航体验。
相关文章:
【Flutter】路由与导航:复杂导航与深度链接
在开发大型 Flutter 应用时,复杂的导航管理是不可避免的。除了基本的页面跳转与返回操作外,很多应用会用到 嵌套路由、页面分组、TabBar 和 Drawer 的结合使用等复杂导航场景,甚至支持 深度链接 和 动态路由。本文将深入探讨这些高级导航技巧…...
07 实战:视频捕获
代码如下: import tkinter as tk # 导入tkinter库,用于创建图形用户界面 from tkinter import ttk, filedialog, messagebox # 导入tkinter的额外部件、文件对话框和消息框 import cv2 # 导入OpenCV库,用于图像处理 import numpy as np # 导入NumPy库,用于数值计算 from P…...

前端页面使用google地图api实现导航功能,开发国外网站免费简单好用
开发国外软件的时候,想使用goole map实现导航等功能,可以使用google的api来做,官方文档地址:https://developers.google.com/maps/documentation/urls/get-started?hlzh-cn ,比如: 支持的请求的操作&…...

UE4 材质学习笔记12(水体反射和折射)
一.水体反射和折射 首先就是要断开所有连接到根节点的线,因为水有很多不同的节点成分,当所有其他节点都在用时 要分辨出其中一个是何效果是很难的。 虚幻有五种不同的方法可以创建反射,虚幻中的大多数场景使用多种这些方法 它们会同时运作。…...

Go:error处理机制和函数
文章目录 error处理机制函数函数作为参数匿名函数匿名函数和闭包闭包运用闭包与工厂模式 error处理机制 本篇总结的是Go中对于错误的处理机制 Go 语言的函数经常使用两个返回值来表示执行是否成功:返回某个值以及 true 表示成功;返回零值(或…...

智能指针(3)
目录 可能问题五: 问题分析: 答案格式: shared_ptr的模拟实现 部分1:引用计数的设计(分考点1) 代码实现: 部分2:作为类所必须的部分(分考点2) 代码实现: 部分3:拷贝构造函数…...

spring源码拓展点3之addBeanPostProcesser
概述 在refresh方法中的prepareBeanFactory方法中,有一个拓展点:addBeanPostProcessor。即通过注入Aware对象从而将容器中的某些值设置到某个bean中。 beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));aware接口调用 …...

【计网】理解TCP全连接队列与tcpdump抓包
希望是火,失望是烟, 生活就是一边点火,一边冒烟。 理解TCP全连接队列与tcpdump抓包 1 TCP 全连接队列1.1 重谈listen函数1.2 初步理解全连接队列1.3 深入理解全连接队列 2 tcpdump抓包 1 TCP 全连接队列 1.1 重谈listen函数 这里我们使用…...

react18中实现简易增删改查useReducer搭配useContext的高级用法
useReducer和useContext前面有单独介绍过,上手不难,现在我们把这两个api结合起来使用,该怎么用?还是结合之前的简易增删改查的demo,熟悉vue的应该可以看出,useReducer类似于vuex,useContext类似…...

排序算法 —— 冒泡排序
目录 1.冒泡排序的思想 2.冒泡排序的实现 3.冒泡排序的总结 1.冒泡排序的思想 冒泡排序的思想就是在待排序序列中依次比较相邻两个元素,将大的or小的元素往后挪,每一趟都能保证将至少一个元素挪动到正确的位置,然后在待排序序列中重复该过…...

QT--文本框 QLineEdit、qtextedit
在Qt中,文本框(QLineEdit 或 QTextEdit)和标签(QLabel)是两种不同的部件(widget),它们的主要区别在于用途和功能: QLabel(标签) 用途࿱…...

Qt编写的modbus模拟器/支持网络和串口以及websocket/支持网络rtu
一、使用说明 1.1 设备模拟-Com 第一步,填写要模拟的设备地址,0表示自动处理,也就是收到什么地址就应答什么地址。第二步,填写对应的串口号和波特率。第三步,单击打开串口,成功后会变成关闭串口字样。单击…...
Standard_Matrix
文章目录 假设我们有一个样本矩阵X,每一列表示一个样本,现在我们要把样本转换成均值为0,方差为1的样本矩阵 X s t a n d a r d X − μ s \begin{equation} X_{standard}\frac{X-\mu}{s} \end{equation} XstandardsX−μpython 测试…...
js 通过input,怎么把选择的txt文件转为base64格式
文章目录 基本概念与作用说明Base64编码File对象相互转换的意义 从File对象到Base64编码从Base64编码到File对象批量转换File对象为Base64编码批量转换Base64编码为File对象功能使用思路思路一:动态生成预览思路二:异步处理与用户反馈思路三:…...
华为HCIP-openEuler认证详解
华为HCIP认证(Huawei Certified ICT Professional)是华为提供的专业级ICT技术认证,它旨在验证技术人员在特定技术领域的专业知识和实践能力。对于华为欧拉(openEuler)方向的HCIP认证,即HCIP-openEuler&…...

YOLO11改进 | 注意力机制 | 添加双重注意力机制 DoubleAttention【附代码+小白必备】
秋招面试专栏推荐 :深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡 在本文中,给大家带来的教程是…...

sentinel原理源码分析系列(四)-ContextEntry
启动和初始化完成后,调用者调用受保护资源,触发sentinel的机制,首先构建或获取Context和获取Entry,然后进入插槽链,决定调用是否通过,怎样通过 上图展示构建Context和获取Entry的类互动图 获取或构建Conte…...

Tcp协议讲解与守护进程
TCP协议:面向链接,面向字节流,可靠通信 创建tcp_server 1.创建套接字 域:依旧选择AF_INET 连接方式: 选择SOCK_STREAM 可靠的 2.bind 3.监听装置 client要通信,要先建立连接࿰…...

学习threejs,THREE.LineDashedMaterial 虚线材质,基于gosper高斯帕曲线生成雪花动画
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:threejs gis工程师 文章目录 一、🍀前言1.1 ☘️THREE.LineDashedMaterial虚…...

LeetCode 热题100之哈希
1.两数之和 思路分析1(暴力法) 双重循环枚举满足num[i] nums[j] target的索引,刚开始不知道如何返回一对索引。后来知道可以直接通过return {i,j}返回索引;注意:j应该从i1处开始,避免使用两次相同的元素…...

SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
【JavaSE】绘图与事件入门学习笔记
-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...

JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
比较数据迁移后MySQL数据库和OceanBase数据仓库中的表
设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能
1. 开发环境准备 安装DevEco Studio 3.1: 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK 项目配置: // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...

【LeetCode】算法详解#6 ---除自身以外数组的乘积
1.题目介绍 给定一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O…...
加密通信 + 行为分析:运营商行业安全防御体系重构
在数字经济蓬勃发展的时代,运营商作为信息通信网络的核心枢纽,承载着海量用户数据与关键业务传输,其安全防御体系的可靠性直接关乎国家安全、社会稳定与企业发展。随着网络攻击手段的不断升级,传统安全防护体系逐渐暴露出局限性&a…...