上一篇在学习MaterialApp的时候,就初步学习了一下路由,这篇就单独深入学习一下路由与导航的内容,以及学习Navigator2.0的内容。
Navigator1.0
一、跳转页面(push入栈)
static Future<T?> push<T extends Object?>(BuildContext context, Route<T> route);
static Future<T?> pushNamed<T extends Object?>(
BuildContext context,
String routeName, {
Object? arguments,
})
static Future<T?> pushReplacement<T extends Object?, TO extends Object?>(BuildContext context, Route<T> newRoute, { TO? result })
static Future<T?> pushReplacementNamed<T extends Object?, TO extends Object?>(
BuildContext context,
String routeName, {
TO? result,
Object? arguments,
})
static Future<T?> pushAndRemoveUntil<T extends Object?>(BuildContext context, Route<T> newRoute, RoutePredicate predicate)
static Future<T?> pushNamedAndRemoveUntil<T extends Object?>(
BuildContext context,
String newRouteName,
RoutePredicate predicate, {
Object? arguments,
})
从定义的方法中可以看出,Navigator1.0中,很多文章习惯性将导航大致可以分为两类,一类是静态的(命名的),一类是动态的;静态导航需要和routes路由搭配使用。但是我更喜欢从行为上来区分,直接入栈和替换入栈很好理解,我们着重理解一下过滤条件的移除入栈这种行为。
pushAndRemoveUntil<T extends Object?>(BuildContext context, Route newRoute, RoutePredicate predicate)
会按次序移除其他的路由,直到遇到被标记的路由(predicate函数返回了true)时停止。若 没有标记的路由,则移除全部。 PS:先执行的Remove,然后再Push  three_page.dart
ModalRoute.withName(‘/’):该逻辑会去匹配根页面,也就是我们的home_page
如果想使用动态导航,并且还可以给页面起个名字,可以使用MaterialPageRoute里面的settings属性(RouteSettings(name: ‘name’)),首页通常可以使用’/'匹配。
import 'package:flutter/material.dart';
import 'package:flutter_hello/home_page.dart';
import 'package:flutter_hello/second_page.dart';
class MyThreePage extends StatelessWidget {
const MyThreePage({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
leading: BackButton(
onPressed: () {
Navigator.pop(context);
},
),
),
body: Center(
child: MaterialButton(
onPressed: () {
Navigator.pushAndRemoveUntil(
context,MaterialPageRoute(builder: (context) => SecondPage()),ModalRoute.withName('/'));
},
child: const Text('第三个页面,跳转到首页'),
),
),
),
);
}
}
pushNamedAndRemoveUntil<T extends Object?>( BuildContext context,String newRouteName,RoutePredicate predicate, {Object? arguments,})
home_page.dart
import 'package:flutter/material.dart';
class HomePage extends StatelessWidget with RouteAware{
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: MaterialButton(
onPressed: () {
Navigator.pushNamed(context, "second");
},
child: const Text(
'下一页',
style: TextStyle(color: Colors.redAccent),
)),
),
),
);
}
}
second_page.dart
import 'package:flutter/material.dart';
class SecondPage extends StatelessWidget {
const SecondPage({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('第二个页面'),
centerTitle: true,
leading: BackButton(
onPressed: () {
Navigator.pop(context);
},
),
),
body: Center(
child: MaterialButton(
onPressed: () {
Navigator.pushNamed(context, "three");
},
child: const Text('第二个页面'),
),
),
),
);
}
}
three_page.dart
import 'package:flutter/material.dart';
import 'package:flutter_hello/home_page.dart';
import 'package:flutter_hello/second_page.dart';
class MyThreePage extends StatelessWidget {
const MyThreePage({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
leading: BackButton(
onPressed: () {
Navigator.pop(context);
},
),
),
body: Center(
child: MaterialButton(
onPressed: () {
Navigator.pushAndRemoveUntil(
context,MaterialPageRoute(builder: (context) => SecondPage()),(Route router) => router.settings.name == "home");
},
child: const Text('第三个页面,跳转到第二页'),
),
),
),
);
}
}
由于之前的页面都是通过命名路由跳转的,所以每个页面都可以用名称作为标识。
1、目前堆栈顺序:home_page -> second_page->three_page 2、three_page通过pushAndRemoveUntil进入到second_page后的栈顺序: home_page -> second_page
二、页面返回(pop出栈)
pop<T extends Object?>(BuildContext context, [ T? result ]
popAndPushNamed<T extends Object?, TO extends Object?>(
BuildContext context,
String routeName, {
TO? result,
Object? arguments,
})
popUntil(BuildContext context, RoutePredicate predicate)
1、pop(直接出栈)

2、popAndPushNamed(当前页面出栈,然后再压入新的页面入栈)

3、popUntil(出栈、出栈、匹配到predicate,则停止出栈)

三、传参
3-1、入栈传参(跳转页面携带数据)
Arguments.dart 自定义的参数类
class Arguments {
String _name = "";
int _age = 0;
String get name => _name;
set name(String value) {
_name = value;
}
int get age => _age;
set age(int value) {
_age = value;
}
}
3-1-1、动态导航传参
使用MaterialPageRoute中的settings属性传递
Arguments arguments = Arguments();
arguments.name = "我是从上个页面传的";
arguments.age = 18;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecondPage(),
settings: RouteSettings(name: 'second', arguments: arguments)));
3-1-2、命名路由传参
使用arguments属性传递
Arguments arguments = Arguments();
arguments.name = "我是从上个页面传的";
arguments.age = 18;
Navigator.pushNamed(context, "second", arguments: _arguments);
3-1-3、目标页面参数的接收
Arguments arguments=ModalRoute.of(context)?.settings.arguments as Arguments;
1、使用ModalRoute.of(context)?.settings.arguments获取 2、使用as强转为相关对象
3-2、出栈传参(返回页面携带数据)
3-2-1、pop<T extends Object?>(BuildContext context, [ T? result ])出栈传参
通过泛型T,携带出栈时携带的参数
Arguments result = Arguments();
result.name = "我是来源于第二个页面的数据";
Navigator.pop(context, result);
3-2-2、返回的目标页通过then接收处理参数
我们回头看一下导航入栈跳转页面的函数的返回值都是Future类型,也就是异步,接收返回页面的数据就是通过这个异步处理的。

Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecondPage(),
settings: RouteSettings(name: 'second', arguments: arguments)))
.then((value){
result=value as Arguments;
setState((){});
});
|