持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第24天,点击查看活动详情
Navigator
Navigator 是管理路由的控件,通常情况下直接使用Navigator.of(context)的方法来跳转页面,之所以可以直接使用Navigator.of(context)是因为在WidgetsApp中使用了此控件,应用程序的根控件通常是MaterialApp,MaterialApp包含WidgetsApp,所以可以直接使用Navigator的相关属性。 需要关注: 1.MaterialApp内置了一个Navigator对象。 2.一个App中多个Navigator对象在调用Navigator.of(context)要注意的事项。 基本用法:
class MyNavigator extends StatefulWidget {
const MyNavigator({Key? key}) : super(key: key);
@override
_MyNavigatorState createState() => _MyNavigatorState();
}
class _MyNavigatorState extends State<MyNavigator> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: getAppBar('Navigator跳转'),
body: buildNavigator,
);
}
Navigator get buildNavigator{
return Navigator(
initialRoute: '/',
onGenerateRoute: (RouteSettings settings) {
WidgetBuilder builder;
switch(settings.name){
case'home':
builder=(context)=>OnePage();
break;
case 'user':
builder=(context)=>TwoPage();
break;
default:
builder=(context)=>OnePage();
break;
}
return MaterialPageRoute(builder: builder, settings: settings);
},
);
}
}
initialRoute表示初始化路由,onGenerateRoute表示根据RouteSettings生成路由。
头条客户端举报场景
点击弹出相关信息,点击其中的局部,会在当前小窗户内跳转到举报页面,效果如下
此场景就是使用Navigator的典型场景,点击举报,并不是全屏切换页面,而是仅仅在当前弹出的页面进行切换。 首页:
class PageA extends StatelessWidget {
const PageA({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Center(
child: Container(
height: 350,
width: 300,
child: Navigator(
initialRoute: '/',
onGenerateRoute: (RouteSettings settins) {
WidgetBuilder builder;
switch (settins.name) {
case '/':
builder = (context) => PageC();
break;
default:
builder = (context) => PageD();
break;
}
return MaterialPageRoute(builder: builder);
},
),
),
);
}
}
Navigator的初始化路由为PageC页面,PageC页面代码如下:
import 'package:demo202112/MyNavigator/wy_paged.dart';
import 'package:flutter/material.dart';
/**
* @Author wywinstonwy
* @Date 2022/10/10 9:48 下午
* @Description:
*/
class PageC extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Card(
child: Column(
children: <Widget>[
_buildItem(Icons.clear, '不感兴趣', '减少这类内容',),
Divider(),
_buildItem(Icons.access_alarm, '举报', '标题夸张,内容质量差 等',
showArrow: true, onPress: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return PageD();
}
)
);
}),
Divider(),
_buildItem(Icons.perm_identity, '拉黑作者:汽车执行', '', ),
Divider(),
_buildItem(Icons.account_circle, '屏蔽', 'seqing视频、驾驶员等',),
],
),
),
);
}
_buildItem(IconData iconData, String title, String content,
{bool showArrow = false, Function() ? onPress}) {
return Row(
children: <Widget>[
Icon(iconData),
SizedBox(
width: 20,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
title,
style: TextStyle(fontSize: 18),
),
Text(
content,
style: TextStyle(
color: Colors.black.withOpacity(.5), fontSize: 14),
)
],
),
),
!showArrow
? Container()
: IconButton(
icon: Icon(Icons.arrow_forward_ios),
iconSize: 16,
onPressed: onPress,
),
],
);
}
}
PageC页面跳转到PageD页面,PageD页面代码如下:
class PageD extends StatefulWidget {
const PageD({Key? key}) : super(key: key);
@override
_PageDState createState() => _PageDState();
}
class _PageDState extends State<PageD> {
@override
Widget build(BuildContext context) {
return Column(
children: [ElevatedButton(onPressed:(){
Navigator.pop(context);
}, child: Text('返回')),
Divider(),
Text('虚假信息举报')
],
);
}
}
Navigator Widget Tree
通过 DevTools 查看一个普通 Flutter App 的 Widget 树结构,与 Navigator 相关的 Widget 如下图:
路由传参和返回携带回调参数
如构建登录页面时候push携带一些参数,登录后返回或者状态改变时候携带回去必要参数,代码如下:
// 定义HomePage
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("登录"),
),
body: ElevatedButton(
onPressed: () async {
// 实现路由跳转
var result = await Navigator.pushNamed(context, 'menu',
arguments: {'name': 'title'});
print(result);
},
child: const Text('登录'),
),
);
}
}
// 定义MenuPage
class MenuPage extends StatelessWidget {
const MenuPage({Key? key}) : super(key: key);
@override
// 接收传参
Widget build(BuildContext context) {
dynamic argumentsData = ModalRoute.of(context)?.settings.arguments;
return Scaffold(
appBar: AppBar(
title: Text('菜单' + argumentsData.toString()),
),
body: ElevatedButton(
onPressed: () {
Navigator.pop(context, {'name': "Navigator.pop传参"});
},
child: const Text("返回"),
),
);
}
}
总结
在实际项目中,对于不需要携带参数的Page可以直接定义全局的Navigator配置routers进行统一管理,对于需要携带参数的可以单独定义工具类进行处理,留出参数和返回参数的情况。