Flutter路由
大约 6 分钟
官网地址:选择你的开发平台,开始使用 | Flutter 中文文档 - Flutter 中文开发者网站 - Flutter
文档地址:第二版序 | 《Flutter实战·第二版》 (flutterchina.club)
FlutterRouter
1、Flutter中的路由
Flutter中给我们提供了两种配置路由跳转的方式:基本路由和命名路由
1.1、基本路由
1.1.1、引入你要跳转的页面
基本陆路由中页面跳转案例
import 'package:flutter/material.dart';
// 引入要跳转的页面
import 'package:bangda/components/YStateComponents/YRouterPage1.dart';
class OrderPage extends StatefulWidget {
const OrderPage({super.key});
State<OrderPage> createState() => _OrderPageState();
}
class _OrderPageState extends State<OrderPage> {
Widget build(BuildContext context) {
return Center(
child: ElevatedButton(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return const YRouterPage1(); //返回你要跳转的页面
}));
},
child: const Text('跳转到新页面')),
);
}
}
1.1.2、跳转传值
在被跳转页面定义一个变量来接收参数
import 'package:flutter/material.dart'; class YRouterPage1 extends StatefulWidget { final String title; final String content; final Object options; const YRouterPage1( {super.key, this.title = "标题", this.content = "内容", required this.options}); State<YRouterPage1> createState() => _YRouterPage1State(); } class _YRouterPage1State extends State<YRouterPage1> { Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(widget.title)), //引用传来的标题 body: Center( child: Column( children: [ Text(widget.content), Text('姓名:${widget.options}') ], //引用传来的内容 ), ), ); } }
要跳转的页面传入参数
Navigator.of(context).push(MaterialPageRoute(builder: (context) { return const YRouterPage1( //传参 title: '今天吃啥子', content: '罗非鱼!', options: { "name": "张三", "age": 18, }, ); //返回你要跳转的页面并且传参 })
1.2、命名路由
当项目比较大时,使用命名路由统一管理
1.2.1、直接抽离一个routers文件来单独管理路由
routers/index.dart
import 'package:flutter/material.dart';
// 引入路由列表
import 'package:bangda/pages/tabbar/index.dart';
import 'package:bangda/components/YRouters/Search.dart';
import 'package:bangda/components/YRouters/Details.dart';
import 'package:bangda/components/YRouters/YForm.dart';
import 'package:bangda/components/YRouters/YShop.dart';
// 定义路由
Map routes = {
"/": (context) => const TabBars(),
"/search": (context) => const RouterSerachPage(),
"/details": (context) => const RouterDetailsPage(),
//传参给YFormPage页面
"/form": (context, {arguments}) => YFormPage(arguments: arguments),
"/shop": (context, {arguments}) => YshopPage(arguments: arguments),
};
// 定义onGenerateRoute 固定写法
var onGenerateRoute = (RouteSettings settings) {
// 相当于跳转路由时的中间件 可以打印settings来做一些操作 比如拦截或者权限判断
// 跳转时执行这里的方法
final String? name = settings.name; //获取settings.name路由名称
final Function? pageContentBuilder =
routes[name]; //赋值跳转的路由给pageContentBuilder
if (pageContentBuilder != null) {
//如果有arguments就传入arguments
if (settings.arguments != null) {
final Route route = MaterialPageRoute(
builder: (context) =>
pageContentBuilder(context, arguments: settings.arguments));
return route;
} else {
//没有arguments就直接跳转
final Route route =
MaterialPageRoute(builder: (context) => pageContentBuilder(context));
return route;
}
}
return null;
};
1.2.2、在main.dart中使用路由
import 'package:flutter/material.dart';
// tabbar
// 引入路由
import 'package:bangda/routes/index.dart';
void main() {
return runApp(MaterialApp(
debugShowCheckedModeBanner: false, //去掉右上角的debug图标
theme: ThemeData(primarySwatch: Colors.blue, primaryColor: Colors.blue),
// home: const TabBars(),//使用路由需要去掉默认的home,并由initialRoute来设置默认页面
initialRoute: "/", //初始化路由,每次打开直接定位到routers中的/,也可以设置为其它页面
onGenerateRoute: onGenerateRoute,
));
}
1.2.3、实现传参
路由中定义(routers/index.dart)
//传参给YFormPage页面 "/form": (context, {arguments}) => YFormPage(arguments: arguments), "/shop": (context, {arguments}) => YshopPage(arguments: arguments),
页面跳转使用
- 固定写法:/form为你配置的页面,arguments为参数对象
import 'package:flutter/material.dart'; class OrderPage extends StatefulWidget { const OrderPage({super.key}); State<OrderPage> createState() => _OrderPageState(); } class _OrderPageState extends State<OrderPage> { Widget build(BuildContext context) { return Center( child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [ const Text('命名路由跳转跳转新页面传参:'), ElevatedButton( onPressed: () { Navigator.pushNamed(context, '/search'); }, child: const Text('跳转到Search')), const SizedBox( height: 20, ), const Text('通过命名路由跳转传参:'), ElevatedButton( onPressed: () { Navigator.pushNamed(context, '/form', arguments: { "name": "py", "age": 23, }); }, child: const Text('跳转到表单')), ElevatedButton( onPressed: () { Navigator.pushNamed(context, '/shop', arguments: { "name": "我是命名路由传过来的", "age": 23, }); }, child: const Text('跳转到shop')) ]), ); } }
接收参数页面
import 'package:flutter/material.dart'; class YFormPage extends StatefulWidget { // 定义接收参数 final Map arguments; const YFormPage({super.key, required this.arguments}); State<YFormPage> createState() => _YFormPageState(); } class _YFormPageState extends State<YFormPage> { void initState() { // TODO: implement initState super.initState(); print(widget.arguments); } Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('form')), body: Center( child: Column(children: [Text('参数${widget.arguments}')]), ), ); } }
1.3、返回上一级路由
Navigator.of(context).pop();
1.4、替换路由(重定向)
从当前页面跳转到search页面,然后从search页面使用pushReplacementNamed跳转到details页面,此时点击返回,则会返回到search页面
Navigator.of(context).pushReplacementNamed('/details');
1.5、返回到根路由
比如我们从用户中心跳转到A页面,然后从A页面跳转到B页面,然后从B跳转到了C页面。这个时候我们想的是C注册成功后返回到用户中心。 这个时候就用到了返回到根路由的方法。
- 可以通过传参来控制返回到tabbar页面的激活index
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (BuildContext context) {
return const TabBars(index: 2,);//返回的页面,这里是返回到tabbar页面传参可控制tabbar页面的index
}), (route) => false);
- 在tabbar页面接收index
import 'package:flutter/material.dart';
// 引入tabbar对应页面
import '../home/home_page.dart';
import '../user/user_page.dart';
import '../order/order_page.dart';
// 自定义底部导航
class TabBars extends StatefulWidget {
final int index; //这是传来的index返回梗路由时传来的index
const TabBars({super.key, this.index = 0});
State<TabBars> createState() => _TabBarsState();
}
class _TabBarsState extends State<TabBars> {
// 所有tabbar列表
final List<Widget> _pageList = const [
HomePage(),
OrderPage(),
UserPage(),
];
int _currentTabs = 0; // 当前激活的tabbar
void initState() {
// TODO: implement initState
super.initState();
//初始化_currentTabs为index,index默认为0,如果传了就使用index职位索引
_currentTabs = widget.index;
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Flutter App'),
backgroundColor: Colors.deepOrange,
),
body: _pageList[_currentTabs], //激活index对应的_pageList
bottomNavigationBar: BottomNavigationBar(
iconSize: 24, //底部菜单的大小默认24
fixedColor: Colors.red, //选中的颜色
currentIndex: _currentTabs, //当前激活index
// type: BottomNavigationBarType.fixed, //如果超过三个tab需要设置为fixed来固定
onTap: (e) {
setState(() {
_currentTabs = e; //重新设置激活的index,重新build
});
},
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: '首页',
),
BottomNavigationBarItem(
icon: Icon(Icons.article),
label: '订单',
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: '我的',
),
],
),
);
}
}
当我们每次打开页面时直接定位到某个页面只需要设置
1.6、Android 和 Ios 使用同样风格的路由跳转动画风格
Material组件库中提供了一个MaterialPageRoute组件,它可以使用和平台风格一致的路由切换动画,如在iOS上会左右滑动切换,而在Android上会上下滑动切换,CupertinoPageRoute是Cupertino组件库提供的iOS风格的路由切换组件如果在Android上也想使用左右切换风格,可以使用CupertinoPageRoute。
1.6.1、routes/index.dart中引入cupertino.dart
import 'package:flutter/cupertino.dart';
1.6.2、routes/index.dart中MaterialPageRoute改为CupertinoPageRoute
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart'; //路由风格切换未ios使用MaterialPageRoute改为CupertinoPageRoute
// 引入路由列表
import 'package:bangda/pages/tabbar/index.dart';
import 'package:bangda/components/YRouters/Search.dart';
import 'package:bangda/components/YRouters/Details.dart';
import 'package:bangda/components/YRouters/YForm.dart';
import 'package:bangda/components/YRouters/YShop.dart';
import 'package:bangda/components/YRouters/Register1.dart';
import 'package:bangda/components/YRouters/Register2.dart';
import 'package:bangda/pages/login/login_page.dart';
// 定义路由
Map routes = {
"/": (context) => const TabBars(),
"/search": (context) => const RouterSerachPage(),
"/details": (context) => const RouterDetailsPage(),
//传参给YFormPage页面
"/form": (context, {arguments}) => YFormPage(arguments: arguments),
"/shop": (context, {arguments}) => YshopPage(arguments: arguments),
"/register1": (context) => const registerPage1(),
"/register2": (context) => const registerPage2(),
"/login": (context) => const loginPage(), //登陆页
};
// 定义onGenerateRoute 固定写法
var onGenerateRoute = (RouteSettings settings) {
// 相当于跳转路由时的中间件 可以打印settings来做一些操作 比如拦截或者权限判断
// 跳转时执行这里的方法
final String? name = settings.name; //获取settings.name路由名称
final Function? pageContentBuilder =
routes[name]; //赋值跳转的路由给pageContentBuilder
if (pageContentBuilder != null) {
//如果有arguments就传入arguments
if (settings.arguments != null) {
final Route route = CupertinoPageRoute(
builder: (context) =>
pageContentBuilder(context, arguments: settings.arguments));
return route;
} else {
//没有arguments就直接跳转
final Route route =
CupertinoPageRoute(builder: (context) => pageContentBuilder(context));
return route;
}
}
return null;
};
控制台按o切换平台,就可以看到不同平台的路由跳转风格
1.7、全局配置主题
return MaterialApp(
debugShowCheckedModeBanner: false,//去除debug
title: 'Flutter Demo',//全局标题
theme: ThemeData(
primarySwatch: Colors.blue,
appBarTheme: const AppBarTheme(
centerTitle: true,//全局标题居中
)
),
initialRoute: "/",
onGenerateRoute: onGenerateRoute,
);