Flutter命名路由
1. 基本介绍
Route 在 Flutter 里是极其重要的部分,用来处理页面跳转。本文主要普通路由,命名路由,以及自定义路由等。
2. 基础功能
- 命名路由 routes
- 路由跳转 push、pop
- 初始路由 initialRoute
- 路由拦截 onGenerateRoute
3. 命名 Route 详解
3.1 容器创建
优雅的编程,我们创建一个 materialapp.dart 文件。
import 'package:flutter/material.dart';
class FMMaterialAppVC extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: Scaffold(
body: AAA(),
),
routes: {
'/bbb': (context) => BBB(),
'/ccc': (context) => CCC(),
'/ddd': (context) => DDD(),
},
);
}
}
class AAA extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('AAA'),
),
body: Center(
child: RaisedButton(
child: Text('点击前往BBB'),
onPressed: (){
Navigator.pushNamed(context, '/bbb');
},
),
),
);
}
}
class BBB extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('BBB'),
),
body: Center(
child: RaisedButton(
child: Text('点击前往CCC'),
onPressed: (){
Navigator.pushNamed(context, '/ccc');
},
),
),
);
}
}
class CCC extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('CCC'),
),
body: Center(
child: RaisedButton(
child: Text('点击前往DDD'),
onPressed: (){
Navigator.pushNamed(context, '/ddd');
},
),
),
);
}
}
class DDD extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('DDD'),
),
body: Center(
child: RaisedButton(
child: Text('点击回到AAA'),
onPressed: (){
Navigator.popUntil(context, (route) => route.isFirst);
},
),
),
);
}
}
3.2 路由跳转方式之 Push 详解
在上文中,我们使用了 pushNamed 方法,推到一个新的页面。
class AAA extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('AAA'),
),
body: Center(
child: RaisedButton(
child: Text('点击前往BBB'),
onPressed: (){
Navigator.pushNamed(context, '/bbb');
},
),
),
);
}
}
3.2.1 Navigator.pushNamed
无参数
Navigator.pushNamed(context, '/bbb');
有参数
final datas = {"data": ["1","2","3"]};
Navigator.pushNamed(context, '/bbb', arguments: datas);
3.2.2 Navigator.push
无参数
Navigator.push(
context,
MaterialPageRoute(
builder: (context){
return BBB();
}
);
有参数,name 可以用来给路由命名,arguments 用来传递参数
final datas = {"data": ["1","2","3"]};
Navigator.push(
context,
MaterialPageRoute(
builder: (context){
return BBB();
},
settings: RouteSettings(
name: '/bbb',
arguments: datas,
),
),
);
3.2.3 Navigator.of(context).pushNamed
基本用法同上
3.2.4 Navigator.of(context).push
基本用法同上
3.3 路由跳转方式之 Push 进阶
注意:写法大同小异,后续就不在赘述传参方式
3.3.1 pushNamedAndRemoveUntil
例如我们页面从AAA->BBB->CCC->DDD,这样进行页面,但是我们希望 CCC 再使用过后就被销毁。使得页面层级变为 AAA-BBB-DDD。
- Navigator.pushNamedAndRemoveUntil
如下方代码,我们在 CCC 中来做处理。 我们的页面层级为 AAA->BBB->CCC->DDD,我们在 CCC 中 push 到 DDD 页面,然后从栈顶开始删除,直到这个route.setting.name == '/bbb',也就是销毁 BBB 与 DDD 中间所有的页面。
class CCC extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('CCC'),
),
body: _listView(context),
);
}
ListView _listView(BuildContext context){
return ListView(
children: [
ListTile(
title: Text("Navigator.pushNamed"),
onTap: (){
Navigator.pushNamed(context, '/ddd');
},
),
ListTile(
title: Text("Navigator.pushNamedAndRemoveUntil"),
onTap: (){
Navigator.pushNamed(context, '/ddd');
},
),
ListTile(
title: Text("Navigator.of(context).pushNamedAndRemoveUntil"),
onTap: (){
Navigator.of(context).pushNamedAndRemoveUntil('/ddd', (route) => route.settings.name == '/ddd');
},
),
ListTile(
title: Text("Navigator.pushNamedAndRemoveUntil - current"),
onTap: (){
Navigator.of(context).pushNamedAndRemoveUntil('/ddd', (route) => route.isCurrent);
},
),
ListTile(
title: Text("Navigator.pushReplacementNamed"),
onTap: (){
Navigator.pushReplacementNamed(context, '/ddd');
},
),
ListTile(
title: Text("Navigator.of(context).pushReplacementNamed"),
onTap: (){
Navigator.of(context).pushReplacementNamed('/ddd');
},
),
ListTile(
title: Text("Navigator.pushReplacement"),
onTap: (){
Navigator.pushReplacement(context,
MaterialPageRoute(
builder: (context){
return DDD();
},
settings: RouteSettings(
name: '/ddd',
),
),
);
},
),
ListTile(
title: Text("Navigator.of(context).pushReplacement"),
onTap: (){
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context){
return DDD();
},
settings: RouteSettings(
name: '/ddd',
),
),
);
},
),
ListTile(
title: Text("Navigator.popAndPushNamed"),
onTap: (){
Navigator.popAndPushNamed(context, '/ddd');
},
),
ListTile(
title: Text("Navigator.of(context).popAndPushNamed"),
onTap: (){
Navigator.of(context).popAndPushNamed('/ddd');
},
),
],
);
}
}
3.3.2 pushReplacementNamed
基本用法同上
3.3.3 popAndPushNamed
基本用法同上
3.4 路由跳转方式之 Pop 详解
class DDD extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('DDD'),
),
body: _listView(context),
);
}
ListView _listView(BuildContext context){
return ListView(
children: [
ListTile(
title: Text('Navigator.pop'),
onTap: (){
Navigator.pop(context);
// final data = {"data":["1","2","3"]};
// Navigator.pop(context, data);
},
),
ListTile(
title: Text('Navigator.pop'),
onTap: (){
Navigator.of(context).pop();
},
),
ListTile(
title: Text('Navigator.canPop'),
onTap: (){
bool canpop = Navigator.canPop(context);
if (canpop) Navigator.pop(context);
},
),
ListTile(
title: Text('Navigator.maybePop'),
onTap: (){
Navigator.maybePop(context);
},
),
],
);
}
}
3.4.1 Navigator.pop
3.4.2 Navigator.of(context).pop
3.4.3 Navigator.canPop
3.4.4 Navigator.of(context).canPop
3.4.5 Navigator.maybePop
3.4.6 Navigator.of(context).maybePop
3.5 路由跳转方式之 Pop 进阶
- 回到栈顶
Navigator.popUntil(context, (route) => route.isFirst);
- 回到指定页面
Navigator.popUntil(context, (route) => route.settings.name == '/bbb');
- 页面堆栈了解
Navigator.popUntil(context, (route) => _lookRoutes(route));
bool _lookRoutes(Route route){
print(route);
return route.isFirst;
}
4. 初始路由 initialRoute
我们注释掉 home 属性,使用 initialRoute 来加载页面
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
// home: Scaffold(
// body: AAA(),
// ),
initialRoute: '/ccc',
routes: {
'/aaa': (context) => AAA(),
'/bbb': (context) => BBB(),
'/ccc': (context) => CCC(),
'/ddd': (context) => DDD(),
},
);
}
5. 未知路由 onUnknownRoute
class FMMaterialAppVC extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => AAA(),
'/bbb': (context) => BBB(),
'/ccc': (context) => CCC(),
'/ddd': (context) => DDD(),
},
onUnknownRoute: (setting){
print(setting);
return MaterialPageRoute(builder: (context) => AAA());
},
);
}
}
class BBB extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('BBB'),
),
body: Center(
child: RaisedButton(
child: Text('点击前往CCC'),
onPressed: (){
Navigator.pushNamed(context, '/cc');
},
),
),
);
}
}
6. 路由拦截 onGenerateRoute
class FMMaterialAppVC extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
// home: Scaffold(
// body: AAA(),
// ),
initialRoute: '/',
routes: {
'/': (context) => AAA(),
'/bbb': (context) => BBB(),
'/ccc': (context) => CCC(),
'/ddd': (context) => DDD(),
},
// onGenerateInitialRoutes: (string){
// return [
// MaterialPageRoute(builder: (context) => AAA()),
// ];
// },
onGenerateRoute: (setting){
print(setting);
return MaterialPageRoute(builder: (context) => CCC());
},
onUnknownRoute: (setting){
print(setting);
return MaterialPageRoute(builder: (context) => AAA());
},
);
}
}
7. 路由拦截独立一个文件
文件目录
import 'package:flutter/material.dart';
import 'package:yuncheng/utils/log_util.dart';
import '../pages/user/login.dart';
import '../pages/user/register.dart';
import '../pages/user/edit_password.dart';
final routes = {
'/login': (context) => const Login(),
'/register': (context, {arguments}) => Register(arguments: arguments),
'/editEassword': (context, {arguments}) => EditPassword(arguments: arguments),
};
// 路由拦截
var onGenerateRoute = (RouteSettings settings) {
// 统一处理
final String? name = settings.name;
LogUtil.v(name);
final Function? pageContentBuilder = routes[name];
if (pageContentBuilder != null) {
if (settings.arguments != null) {
final Route route = MaterialPageRoute(
builder: (context) =>
pageContentBuilder(context, arguments: settings.arguments));
return route;
} else {
final Route route =
MaterialPageRoute(builder: (context) => pageContentBuilder(context));
return route;
}
}
};
main.dart
import 'package:flutter/material.dart';
import 'package:yuncheng/utils/log_util.dart';
import 'pages/my_bottom_app_bar.dart';
import 'utils/color.dart';
import 'routes/routes.dart';
void main() {
// 初始化日志系统
LogUtil.init(tag: "package:yuncheng-utils", isDebug: true);
runApp(const Myapp());
}
class Myapp extends StatelessWidget {
const Myapp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "电商系统",
theme: ThemeData(
primarySwatch:
createMaterialColor(const Color.fromARGB(255, 178, 10, 8)),
),
debugShowCheckedModeBanner: false,
home: const MyBottomAppBar(),
onGenerateRoute: onGenerateRoute,
);
}
}