【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处开始,避免使用两次相同的元素…...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...
Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...
大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...
视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...
【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...
