背景:管理多个⻚⾯时有两个核⼼概念和类:Route 和 Navigator。 ⼀个 route 是⼀个屏幕或⻚⾯的抽象,Navigator 是管理 route 的 Widget。Navigator 可以通过 route ⼊栈和出栈来实现⻚⾯之间的跳转。
Navigator 提供了⼀系列⽅法来管理路由栈,其中最常⽤的两个⽅法是push()和pop(),它们的含义如下。
- push():将给定的路由⼊栈,返回值是⼀个Future对象,⽤以接收路由出栈时的返回数据。
- pop():将栈顶路由出栈,返回结果为⻚⾯关闭时返回给上⼀个⻚⾯的数据。
匿名路由
基本⽤法仅适⽤于⻚⾯较少的场景。
具体代码实现:
// 跳转:
Navigator.push()
// 退出:
Navigator.pop()
具体代码实现:
import 'package:flutter/material.dart';
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Home(),
debugShowCheckedModeBanner: false, );
}
}
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('⾸⻚'),
),
body: Center(
child: RaisedButton(
child: Text('跳转到商品⻚'),
onPressed: () => Navigator.push(
context,
MaterialPageRoute(builder: (context) => Product())
)),),);}}
class Product extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('商品⻚'),
),
body: Center(
child: RaisedButton(
child: Text('返回⾸⻚'),
onPressed: () => Navigator.pop(context)
),),);}
跳转⻚⾯使⽤的是 Navigator.push() ⽅法,该⽅法可以将⼀个新的路由添加到由 Navigator 管理的路由对象 的栈顶。⽽创建新的路由对象使⽤的是 MaterialPageRoute,MaterialPageRoute 是 PageRoute 的⼦类,定义了路由创建及切换时过渡动画的相关接⼝及属性。
命名路由
所谓命名路由,就是给⻚⾯起⼀个别名,然后使⽤⻚⾯的别名就可以打开它,使⽤此种⽅式来管理路由,使得路由的管理更加清晰直观。 要想通过别名来指定⻚⾯切换,必须先给应⽤程序 MaterialApp 提供⼀个⻚⾯名称映射规则,即路由表。路由表是⼀个Map的结构,其中key对应⻚⾯名字,value则是对应的⻚⾯,如下所示:
MaterialApp(
// ... // 其他配置
routes:{ // 注册路由(路由表)
'first': (context) => FirstPage(),
'second': (context) => SecondPage(),
},
initialRoute: 'first', // 初始路由⻚⾯
);
使⽤命名路由
// 跳转
Navigator.pushNamed(context, 'second'); // second 表示⻚⾯别名
// 返回
Navigator.pop(context);
未知路由
如果打开⼀个不存在的路由⻚⾯。可以跳转到⼀个统⼀的错误⻚⾯(相当于 Web 端的 404)。在注册路由表时, Flutter 提供了⼀个 UnknownRoute 属性,⽤来对未知的路由标识符,进⾏统⼀的⻚⾯跳转处理,如下所示:
MaterialApp(
// ... // 其他配置
routes:{},
onUnknownRoute: (RouteSettings setting) => MaterialPageRoute(builder: (context) =>
UnknownPage()), // 错误路由处理,返回UnknownPage
);
class UnknownPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('404'),
),
body: Center(
child: Text('未知⻚⾯')
),
);
}
}
动态路由 动态路由是指通过 onGenerateRoute 属性指定的路由,可以根据访问路径进⾏动态匹配和拦截。
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
// 通过 onGenerateRoute ⽣成动态路由
onGenerateRoute: (settings) {
// Handle '/'
if (settings.name == '/') {
return MaterialPageRoute(builder: (context) => HomeScreen());
}
// Handle '/details/:id'
var uri = Uri.parse(settings.name);
if (uri.pathSegments.length == 2 &&
uri.pathSegments.first == 'details') {
var id = uri.pathSegments[1];
return MaterialPageRoute(builder: (context) => DetailScreen(id: id));
}
return MaterialPageRoute(builder: (context) => UnknownScreen());
},
);
}
}
路由传参
//普通路由传参
Navigator.push(context,
MaterialPageRoute(builder: (context) {
return BlogDetail(id: blogItem['id'],);
}));
//接收参数
class BlogDetail extends StatefulWidget {
// 构造函数
BlogDetail({Key key, @required this.id}) : super(key: key);
final int id;
}
//命名路由传参
Navigator.pushNamed(
context,"/homePage",arguments: {'title': "命令路由传递过来的title"}
);
//接收参数
class HomePage extends StatelessWidget {
final Map arguments;
HomePage({Key key, this.arguments});
String title = arguments['title'];
// ......
}