Flutter03-核心基础-路由
Flutter03-核心基础-路由
路由
路由(Route)在移动开发中通常指页面(Page),这跟 Web 开发中单页应用的 Route 概念意义是相同的,Route 在 Android中 通常指一个 Activity,在 iOS 中指一个 ViewController。
所谓路由管理,就是管理页面之间如何跳转,通常也可被称为导航管理。
Flutter 中的路由管理和原生开发类似,无论是 Android 还是 iOS,导航管理都会维护一个路由栈,路由入栈(push)操作对应打开一个新页面,路由出栈(pop)操作对应页面关闭操作,而路由管理主要是指如何来管理路由栈。
简单示例
添加了一个打开新路由的按钮,点击该按钮后就会打开新的路由页面,效果如图所示。
class NewRoute extends StatelessWidget {
const NewRoute({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('New Route'),
),
body: const Center(
child: Text('This is new route'),
),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Homepage"),
),
body: Center(
child: TextButton(
child: const Text('open new route'),
onPressed: () {
// 导航到新路由
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return const NewRoute();
}),
);
},
),
),
);
}
}
void main(List<String> args) {
runApp(const MaterialApp(
title: 'My App',
home: HomePage(),
));
}
MaterialPageRoute
MaterialPageRoute继承自PageRoute类,PageRoute类是一个抽象类,表示占有整个屏幕空间的一个模态路由页面,它还定义了路由构建及切换时过渡动画的相关接口及属性。MaterialPageRoute 是 Material组件库提供的组件,它可以针对不同平台,实现与平台页面切换动画风格一致的路由切换动画。
-
对于 Android,当打开新页面时,新的页面会从屏幕底部滑动到屏幕顶部;当关闭页面时,当前页面会从屏幕顶部滑动到屏幕底部后消失,同时上一个页面会显示到屏幕上。
-
对于 iOS,当打开页面时,新的页面会从屏幕右侧边缘一直滑动到屏幕左边,直到新页面全部显示到屏幕上,而上一个页面则会从当前屏幕滑动到屏幕左侧而消失;当关闭页面时,正好相反,当前页面会从屏幕右侧滑出,同时上一个页面会从屏幕左侧滑入。
Navigator
Navigator是一个路由管理的组件,它提供了打开和退出路由页方法。Navigator通过一个栈来管理活动路由集合。通常当前屏幕显示的页面就是栈顶的路由。
Navigator提供了一系列方法来管理路由栈,在此我们只介绍其最常用的两个方法:
Future push(BuildContext context, Route route)
将给定的路由入栈(即打开新的页面),返回值是一个Future对象,用以接收新路由出栈(即关闭)时的返回数据。
bool pop(BuildContext context, [ result ])
将栈顶路由出栈,result 为页面关闭时返回给上一个页面的数据。
路由传值
下面我们通过一个例子来演示:创建一个TipRoute路由,它接受一个提示文本参数,负责将传入它的文本显示在页面上,另外TipRoute中我们添加一个“返回”按钮,点击后在返回上一个路由的同时会带上一个返回参数,下面我们看一下实现代码。
class RouterTestRoute extends StatelessWidget {
const RouterTestRoute({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Center(
child: ElevatedButton(
onPressed: () async {
// 打开`TipRoute`,并等待返回结果
var result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return const TipRoute(text: '我是提示xxx');
}),
);
//输出TipRoute路由返回结果
print('路由返回值:$result');
},
child: const Text('打开提示页'),
),
);
}
}
class TipRoute extends StatelessWidget {
const TipRoute({
Key? key,
required this.text, // 接收一个text参数
}) : super(key: key);
final String text;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('提示'),
),
body: Padding(
padding: const EdgeInsets.all(18),
child: Center(
child: Column(
children: [
Text(text),
ElevatedButton(
onPressed: () => Navigator.pop(context, '我是返回值'),
child: const Text('返回'),
),
],
),
),
),
);
}
}
void main(List<String> args) {
runApp(const MaterialApp(
title: 'My app',
home: RouterTestRoute(),
));
}
运行上面代码,点击RouterTestRoute页的“打开提示页”按钮,会打开TipRoute页,运行效果如图所示下:
在TipRoute页中有两种方式可以返回到上一页;第一种方式是直接点击导航栏返回箭头,第二种方式是点击页面中的“返回”按钮。这两种返回方式的区别是前者不会返回数据给上一个路由,而后者会。
I/flutter (27896): 路由返回值: 我是返回值
I/flutter (27896): 路由返回值: null
命名路由
所谓“命名路由”(Named Route)即有名字的路由,我们可以先给路由起一个名字,然后就可以通过路由名字直接打开新的路由了,这为路由管理带来了一种直观、简单的方式。
- 路由表
要想使用命名路由,我们必须先提供并注册一个路由表(routing table),这样应用程序才知道哪个名字与哪个路由组件相对应。其实注册路由表就是给路由起名字,路由表的定义如下:
Map<String, WidgetBuilder> routes;
它是一个Map,key为路由的名字,是个字符串;value是个builder回调函数,用于生成相应的路由widget。我们在通过路由名字打开新路由时,应用会根据路由名字在路由表中查找到对应的WidgetBuilder回调函数,然后调用该回调函数生成路由widget并返回。
- 注册路由表
- 通过路由名打开新路由页
- 命名路由参数传递
// 命名路由
class NewRoute extends StatelessWidget {
const NewRoute({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
// 获取路由参数
String arg = ModalRoute.of(context)!.settings.arguments as String;
return Center(
child: Text(
'New Route, arguments:$arg',
textDirection: TextDirection.ltr,
),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Center(
child: TextButton(
onPressed: () {
// 命名路由参数传递
Navigator.of(context).pushNamed('new_page', arguments: 'Hi');
},
child: Text('跳转到NewRoute'),
),
);
}
}
void main(List<String> args) {
runApp(MaterialApp(
title: 'My app',
initialRoute: '/', //名为"/"的路由作为应用的home(首页)
theme: ThemeData(
primarySwatch: Colors.blue,
),
// 注册路由表
routes: {
'new_page': (context) => const NewRoute(),
"/": (context) => const HomePage(),
},
));
}