Flutter学习之旅 - 路由

news2024/11/15 23:48:32

文章目录

      • Flutter路由介绍
      • 普通路由
        • 普通路由传值
      • 命名路由
        • 将`routes`的配置提到外面(使用的是Map)
        • 命名路由传值
      • 路由跳转
      • 返回上一级路由
      • 替换路由
      • 返回到根路由
      • 返回Tabs后到指定页面

Flutter路由介绍

flutter中的路由通俗就是页面跳转。在Flutter中通过Navigator(学过reactjs小程序的小伙伴应该很清楚)组件管理路由导航
Flutter给我们提供了俩种配置路由跳转的方式: 1.基本路由 2.命名路由

普通路由

//格式
Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) {
  return const WidgetName();
}));
//search.dart (跳转的页面)
import 'package:flutter/material.dart';

class SearchPage extends StatefulWidget {
  const SearchPage({super.key});

  
  State<SearchPage> createState() => _SearchPageState();
}

class _SearchPageState extends State<SearchPage> {
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("你好"),
      ),
      body: const Text("搜索页面"),
    );
  }
}
//home.dart
import 'package:flutter/material.dart';
import 'package:flutter_luyou_learn/pages/search.dart'; //引入SearchPage

...
class _HomePageState extends State<HomePage>
    with SingleTickerProviderStateMixin {
  late TabController _tabController;
  
  void initState() {
    super.initState();
    _tabController = TabController(length: 5, vsync: this);
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
          backgroundColor: const Color.fromRGBO(255, 255, 255, 1),
          leading: const CircleAvatar(
            backgroundImage: NetworkImage(imageUrl(String)),
          ),
          title: ElevatedButton(
            onPressed: () {
            //主要(路由)
              Navigator.of(context)
                  .push(MaterialPageRoute(builder: (BuildContext context) {
                return const SearchPage();
              }));
            },
            child: const Text("搜索"),
          ),
          bottom: TabBar(
            controller: _tabController,
            indicatorColor: Colors.red,
            labelColor: Colors.red,
            unselectedLabelColor: Colors.black,
            tabs: const [
              Tab(child: Text("直播")),
              Tab(child: Text("推荐")),
              Tab(child: Text("热门")),
              Tab(child: Text("动画")),
              Tab(child: Text("影视")),
            ],
          )),
      body: TabBarView(
        controller: _tabController,
        children: const [
          Text("直播页"),
          Text("推荐页"),
          Text("热门页"),
          Text("动画页"),
          Text("影视页")
        ],
      ),
    );
  }
}

模板的知识请看这里

普通路由传值

跳转传值和调用组件传值的实现方法是一样的

//download.dart (新建一个组件)
import 'package:flutter/material.dart';

class DownloadPage extends StatefulWidget {
  final String titleMsg; //像传值一样定义
  const DownloadPage({
    super.key,
    this.titleMsg = "已经缓存视频", //没有传入默认使用这个
  });

  
  State<DownloadPage> createState() => _DownloadPageState();
}

class _DownloadPageState extends State<DownloadPage> {
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("离线缓存"),
      ),
      // body: const Text("你好"),
      body: _DownloadPageBody(
        titleMsg: widget.titleMsg, //获取DownloadPage里的属性titleMsg
      ),
    );
  }
}

class _DownloadPageBody extends StatelessWidget {
  String titleMsg;
  _DownloadPageBody({Key? key, required this.titleMsg}) : super(key: key);
  
  Widget build(BuildContext context) {
    return Column(
      children: [
        Container(
          width: 100,
          height: 50,
          decoration: const BoxDecoration(),
          child: Text(titleMsg),//显示输出
        )
      ],
    );
  }
}

//my.dart(关键代码)
ElevatedButton(
  onPressed: () {
    Navigator.of(context).push(MaterialPageRoute(
      builder: (BuildContext context) {
        return const DownloadPage(titleMsg: "测试",);
        //return const DownloadPage();
      }));
  },
  child: const Icon(Icons.ads_click),//随意
),

命名路由

//lib.main.dart
import 'package:flutter/material.dart';
import 'package:项目名/pages/tabs.dart';
import 'package:项目名/pages/tabs/my.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  
  Widget build(BuildContext context) {
    return MaterialApp(
      //记住这里不能写const MaterialApp()
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      // home: Tabs(),  //去除
      routes: {//添加
        '/': (context) => const Tabs(),
        '/search': (context) => const SearchPage()
      },
    );
  }
}
//lib/pages/tabs.dart
import 'package:flutter/material.dart';
//import 'package:项目名/lib目录下的文件或文件夹'
import 'package:项目名/pages/tabs/home.dart';
import 'package:项目名/pages/tabs/my.dart';

class Tabs extends StatefulWidget {
  const Tabs({super.key});

  
  State<Tabs> createState() => _TabsState();
}

class _TabsState extends State<Tabs> {
  int _currentIndex = 0;
  //添加
  final List<Widget> _pages = const [HomePage(), MyPage()];
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: null,
      body: _pages[_currentIndex], //修改
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _currentIndex,
        onTap: (index) {
          //index:点击索引值
          // print(index);
          setState(() {
            _currentIndex = index;
          });
        },
        items: const [
          BottomNavigationBarItem(icon: Icon(Icons.home), label: "首页"),
          BottomNavigationBarItem(
              icon: Icon(Icons.my_library_add_outlined), label: "我的")
        ],
      ),
    );
  }
}

//home.dart(命名路由跳转关键代码)
ElevatedButton(
  onPressed: () {
    //格式:Navigator.pushNamed(context, '/跳转的路径名称');
    Navigator.pushNamed(context, '/search'); //命名路由跳转
  },
  child: const Text("搜索"),
),

routes的配置提到外面(使用的是Map)

  1. 配置主函数main.dart
//main.dart
import 'package:flutter/material.dart';
import 'package:mmly_learn_flutter/pages/tabs.dart';
import 'package:mmly_learn_flutter/pages/tabs/my.dart';
import 'package:mmly_learn_flutter/pages/tabs/search.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  MyApp({super.key});

  //1、配置路由
  Map<String, WidgetBuilder> routes = {
    '/': (context) => const Tabs(),
    '/search': (context) => const SearchPage()
  };
  // This widget is the root of your application.
  
  Widget build(BuildContext context) {
    return MaterialApp(
      //记住这里不能写const MaterialApp()
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      // home: Tabs(),
      initialRoute: "/", //初始化路由
      onGenerateRoute: (RouteSettings settings) {
        //2、配置路由(先把它当作固定格式)
        final String? name = settings.name;
        final Function? pageContrentBuilder = routes[name];
        if (pageContrentBuilder != null) {
          if (settings.name != null) {
            final Route route = MaterialPageRoute(
                builder: (context) => pageContrentBuilder(context,
                    arguments: settings.arguments));
            return route;
          }
          else {
            final Route route = MaterialPageRoute(
              builder: (context) => pageContrentBuilder!(context));
            return route;
          }
        } 
        return null;
      },
    );
  }
}

命名路由传值

跳转页面后传值

//search.dart(找到你需要跳转的页面进行处理)
import 'package:flutter/material.dart';

class SearchPage extends StatefulWidget {
  final Map arguments; //在需要传值的页面传入命名路由导航的argments
  const SearchPage({super.key, required this.arguments});

  
  State<SearchPage> createState() => _SearchPageState();
}

class _SearchPageState extends State<SearchPage> {
  
  void initState() {
    super.initState();
    print(widget.argments); //查看传入的值
    // print(widget.arguments['name']);//赋值格式
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("搜索"),
      ),
    );
  }
}
//main.dart(配置了routes的组件中,一般是main.dart)
Map<String, WidgetBuilder> routes = {
  '/': (context) => const Tabs(),
  '/search': (context, {argments}) => SearchPage(arguments: arguments)
};
//home.dart(点击跳转的按钮或者组件)
Navigator.pushNamed(context, '/search', arguments: {"title": "我是命名路由传值", "aid": 10}); 

class MyApp extends StatelessWidget {
  MyApp({Key? key}) : super(key: key);

  //1、配置路由
  Map<String, WidgetBuilder> routes = {
    '/': (context) => const Tabs(),
    '/search': (context, {arguments}) => SearchPage(arguments: arguments),
    '/login': (context) => const LoginPage(),
    '/loginFirst': (context) => const LoginFirstPage()
  };
  // This widget is the root of your application.
  
  Widget build(BuildContext context) {
    return MaterialApp(
      //记住这里不能写const MaterialApp()
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      // home: Tabs(),
      initialRoute: "/", //初始化路由
      onGenerateRoute: (RouteSettings settings) {
        //2、配置路由(先把它当作固定格式)
        final String? name = settings.name;
        final Function? pageContrentBuilder = routes[name];
        if (pageContrentBuilder != null) {
          if (settings.arguments != null) {
            final Route route = MaterialPageRoute(
                builder: (context) => pageContrentBuilder(context,
                    arguments: settings.arguments));
            return route;
          } else {
            final Route route = MaterialPageRoute(
                builder: (context) => pageContrentBuilder(context));
            return route;
          }
        }
        return null;
      },
    );
  }
}

上面写法后错误了

上图有可能(context, {argments}) => SearchPage(arguments: arguments)写成了(context, argments) => SearchPage(arguments: arguments)

  • settings: RouteSettings("/...",null)
  • settings.name: /...(路径名),
  • settings.arguments: null(传入的值)

路由跳转

我们希望跳转后接着跳转到另一个页面

  1. 首先实现1次跳转(步骤跟上面的知识一致,我们这里就以login为案例)
//lib/pages/user/login.dart
import 'package:flutter/material.dart';

class LoginPage extends StatefulWidget {
  const LoginPage({super.key});

  
  State<LoginPage> createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("登录页面"),
      ),
      body: Column(
        children: [ElevatedButton(onPressed: () {
        /*
        //返回上一级
        Navigator.of(context).pop();
        */}, child: const Text("执行登录"))],
      ),
    );
  }
}
//lib/main.dart(路由配置,不一定非是这个文件)
Map<String, WidgetBuilder> routes = {
    '/': (context) => const Tabs(),
    '/search': (context, {arguments}) => SearchPage(arguments: arguments),
    '/login': (context) => const LoginPage() //添加
  };
//lib/pages/tabs/home.dart(按自己喜好的文件)

返回上一级路由

//返回上一级
Navigator.of(context).pop();

替换路由

//当然替换的路由路径(/registerSecound)也要添加在Map routes配置中
//注意: 这个方法是将之前的页面进行替换(覆盖),所以之前的页面是销毁的
Navigator.of(context).pushReplacementNamed('/registerSecound')

返回到根路由

  1. 是使用Scaffold组件appBar
  2. 通过Navigator.of(context).pushAndRemoveUntil进行返回
Navigator.of(context).pushAndRemoveUntil(
  MaterialPageRoute(builder: (BuildContext context) {
    return const Tabs(); //返回到根页面
}), (route) => false);

返回Tabs后到指定页面

因为之前学习的时候有_currentIndex来指定底部在那个页面,所以

import 'package:flutter/material.dart';
//import 'package:项目名/lib目录下的文件或文件夹'
import 'package:mmly_learn_flutter/pages/tabs/home.dart';
import 'package:mmly_learn_flutter/pages/tabs/my.dart';

class Tabs extends StatefulWidget {
  final int index; //添加
  const Tabs({super.key, this.index = 0}); //添加

  
  State<Tabs> createState() => _TabsState();
}

class _TabsState extends State<Tabs> {
  int _currentIndex = 0;
  
  void initState() {
    //添加
    super.initState();
    _currentIndex = widget.index;
  } //修改

  //添加
  final List<Widget> _pages = const [HomePage(), MyPage()];
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: null,
      body: _pages[_currentIndex],
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _currentIndex,
        onTap: (index) {
          setState(() {
            _currentIndex = index;
          });
        },
        items: const [
          BottomNavigationBarItem(icon: Icon(Icons.home), label: "首页"),
          BottomNavigationBarItem(
              icon: Icon(Icons.my_library_add_outlined), label: "我的")
        ],
      ),
    );
  }
}

主要是添加(可以在上图代码中查看)

final int index;
this.index = 0
void initState() {...;_currentIndex = widget.index;}
Navigator.of(context).pushAndRemoveUntil(
                        MaterialPageRoute(builder: (BuildContext context) {
                      return const Tabs(index: 1); //注意: 这下标是以0开始的
                    }), (route) => false);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/510039.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

idea使用Database连接数据库报错ssm证书验证失败无法建立安全连接

项目场景&#xff1a; idea使用Database连接数据库报错ssm证书验证失败无法建立安全连接 问题描述 [08S01] 驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接。错误:“The server selected protocol version TLS10 is not accepted by client preferenc…

Java Agent

摘要 ​ JavaAgent就是Java探针&#xff0c;是一个JVM插件&#xff0c;常用于代码热更新&#xff0c;AOP&#xff0c;JVM监控等功能。这个技术对大多数的同学来说可能有点陌生&#xff0c;但是对Java软件开发人员来说肯定都多多少少接触过&#xff0c;只是相对其原理&#xff…

Selenium技术在CentOS6.8系统的腾讯云服务器上的相关使用

目录 一、解释说明二、操作过程中Linux相关命令1、下载谷歌浏览器2、查看谷歌浏览器的版本3、下载对应版本的谷歌驱动&#xff08;或者本地上传&#xff09;4、解压下载的文件5、移动下载文件6、给予文件执行权限7、更新pip3到最高版本8、下载Selenium第三方库9、正式测试10、最…

C#学习笔记--由浅至深理解IEnumerable和IEnumerator

目录 前言总结 IEnumerable 和 IEnumeratorIEnumerable是什么&#xff1f;IEnumerator是什么&#xff1f;总结 结尾预告 前言 上篇文章我是自己实现了一个容器C#学习笔记–实现一个可以重复权重并且能够自动排序的容器–MultiplySortedSet 写完之后突然想到一个问题&#xff…

PMP课堂模拟题目及解析(第6期)

51. 管理层将一个国际项目分配给一位新项目经理。这是该项目经理第一次与团队合作&#xff0c;团队成员位于两个国家&#xff0c;数量平均分布&#xff0c;一个团队由最合适作为个人工作的成员组成&#xff0c;另一个团队由最适合作为团队工作的成员组成。项目经理该怎么做&am…

抖音商城小程序搭建的注意事项

抖音商城小程序已经成为了越来越多电商企业的选择&#xff0c;毕竟它具有强大的用户资源和社交传播力。但是&#xff0c;在搭建抖音商城小程序的过程中&#xff0c;还有一些需要注意的事项。 1、制定明确的策略和目标 在搭建抖音商城小程序前&#xff0c;必须事先制定明确的策…

65.网站个性框架

之前介绍过集中个性网站 严肃优雅型极简主义普通/中性大胆/自信平静祥和创业/上进俏皮/好玩 严肃优雅型 概述 奢华和优雅的设计&#xff0c;基于细小的衬线字体、金色或粉色的颜色和高质量的大图片。 行业 房地产、高端时尚、饰品类&#xff0c;奢侈产品或服务 排版 有衬…

(构造函数的补充2)类型转换与临时变量(新对象)的生成与explicit关键字,类的静态成员变量与成员函数及其应用

(构造函数的补充2)类型转换与临时变量(新对象)的生成与explicit关键字 如果说一个构造函数是单个参数&#xff0c;或者说有多个参数但是第一个参数没有默认值&#xff0c;而其余均有默认值&#xff0c;这时候就特别需要注意类型转换的问题。首先必须得知道的一点就是说一旦有类…

Vue中的键盘事件

目录 一、Vue中的键盘事件的类型 二、keycode指定具体的按键 三、Vue中常用的按键别名 四、Vue自定义按键 五、实现多个按键一起触发事件 一、Vue中的键盘事件的类型 keydown:键盘按下就会触发 keyup:键盘抬起就会触发 二、keycode指定具体的按键 在键盘中&#xff0c;每一…

JMeter测试工具设置中文

JMeter测试工具设置中文 在JMeter中&#xff0c;默认情况下是英文的&#xff0c;如果需要使用中文进行测试&#xff0c;则需要进行如下设置&#xff1a; 第一步、设置JMeter语言选项 在JMeter运行时界面的“Options”菜单中&#xff0c;选择“Choose Language”&#xff0c;…

2023.05.10- 使用Loopback Scaler来改善Stable Diffusion的绘图效果

简介 Loopback Scaler可以添加画面细节 渣图挽救者&#xff1a;在图生图中对原图迭代重绘&#xff0c;修复渣图。脚本在多个循环中处理输入图像&#xff0c;每个循环提高分辨率并优化图像质量。然后&#xff0c;一个循环的图像结果作为下一个循环的输入图像插入&#xff0c;该…

FE_Vue框架的执行流程详解

1 分析脚手架结构 2 整个流程 执行npm run serve&#xff0c;随后来到src中找到【整个项目的入口文件】main.js&#xff0c;这个js页面中引入了Vue、App.vue、关闭了提示等。 // ps: 该文件是整个项目的入口文件 // step1 引入Vue import Vue from vue // step2 引入App组件-…

Android9.0 Charles 模拟器抓包

目录 只想做条安静的咸鱼&#xff0c;混吃等死又一天 一、下载并安装配置Charles 二、下载安装Postern 三、测试抓包 一、下载并安装配置Charles 1.Charles下载网址&#x1f447; Charles Web Debugging Proxy • HTTP Monitor / HTTP Proxy / HTTPS & SSL Proxy / Rev…

EasyPoi导出,设置不同列的字体颜色(修改easypoi 3.1.0版本源码)

声明&#xff1a;代码以esaypoi 3.1.0版本为基础&#xff0c;基本上新的代码都是直接copy源码的&#xff0c;只是稍微修改了源码&#xff1b;仍然需要导入该依赖是 <dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-base</artifac…

数据建模三范式说明

三范式&#xff1a; 1.原子性&#xff1a;属性不可分割 2.唯一性&#xff1a;不能存在部分依赖 3.非冗余性&#xff1a;要求任何字段不能由其他字段派生出来、确保每列都和主键列直接相关,而不是间接相关)

案例|九江银行Zabbix监控系统实践

Zabbix监控平台建设历程 九江银行Zabbix监控系统实践&#xff0c;共分为三个部分&#xff1a; 1.Zabbix监控平台的建设历程 2.Zabbix实践经验分享 3.对未来监控的展望。 项目背景 建立新的一体化基础监控平台。为适应数字化转型的需要、新技术发展的需要及业务连续性的需…

关于使用Lombok的注意事项

文章目录 1、Lombok简介2、使用Lombok的问题2.1 驼峰问题2.2 相同的字符串不同的大小写 3、关于使用Lombok的总结4、写在最后 1、Lombok简介 Lombok项目是一个Java库&#xff0c;它会自动插入您的编辑器和构建工具中&#xff0c;从而为你优化Java代码。通过注解的方式代替我们手…

注入攻击(二)--------HTML(有源码)

前序文章 注入攻击&#xff08;一&#xff09;--------SQL注入(结合BUUCTF sqli-labs) 目录 示例网站搭建1.搭建LAMP开发环境1. MySQL2. PHP3. Apache 写在示例前示例1.反射型HTML注入页面效果源码 示例2.钓鱼表单页面效果源码 示例3.存储型HTML注入页面效果源码 示例网站搭建 …

【Docker】使用 Docker 部署 Maven 仓库

在本文中&#xff0c;将介绍如何使用 Docker 部署一个 Maven 本地私服。Maven 私服可以帮助我们管理和共享本地的 Maven 依赖&#xff0c;提高开发效率。本文将使用 Sonatype Nexus 作为 Maven 私服&#xff0c;并使用 Docker Compose 来部署和管理容器。 准备工作 在开始之前…

mysql数据库在windows服务器下安装

一、mysql安装包下载 官网下载地址&#xff1a;mysql安装包下载 如图所示&#xff1a; 二、配置my.ini文件 解压后的文件尽量不要放在C盘&#xff08;内存小&#xff09;&#xff0c;解压后如下图所示 在上图所示根目录下配置my.ini文件 1、右键创建一个文本&#xff08;.text…