在 Flutter 中,路由技术的核心概念包括两个要素:Route 和 Navigator Route 代表应用中的一个页面,它包含了页面的布局、逻辑以及生命周期等信息。在 Flutter 中,Route通常是一个继承自
PageRoute的类。
Route
PageRoute是一个抽象类,表示一个可以用于Navigator的页面。它包含了页面的构建方法、过渡动画以及页面的生命周期回调等属性。在实际开发中,我们通常会使用以下两种PageRoute:MaterialPageRoute或CupertinoPageRoute:
-
MaterialPageRoute:一个实现了Material Design风格的页面路由,它提供了平台特定的页面切换动画。在Android设备上,页面从底部滑入;在iOS设备上,页面从右侧滑入。如:// 使用MaterialPageRoute创建一个新页面 MaterialPageRoute(builder: (context) => NewPage());MaterialPageRoute({ WidgetBuilder builder, RouteSettings settings, bool maintainState = true, bool fullscreenDialog = false, }) -
builder是一个 WidgetBuilder 类型的回调函数,它的作用是构建路由页面的具体内容,返回值是一个 widget。我们通常要实现此回调,返回新路由的实例。 -
settings包含路由的配置信息,如路由名称、是否初始路由(首页)。 -
maintainState:默认情况下,当入栈一个新路由时,原来的路由仍然会被保存在内存中,如果想在路由没用的时候释放其所占用的所有资源,可以设置maintainState为 false。 -
fullscreenDialog表示新的路由页面是否是一个全屏的模态对话框,在 iOS 中,如果fullscreenDialog为true,新页面将会从屏幕底部滑入(而不是水平方向)。 -
CupertinoPageRoute:一个实现了Cupertino风格(iOS风格)的页面路由,它提供了iOS平台特定的页面切换动画。如:// 使用CupertinoPageRoute创建一个新页面 CupertinoPageRoute(builder: (context) => NewPage());
Navigator
Navigator 是一个管理应用页面栈的组件,它负责处理页面之间的跳转、导航以及参数传递等操作。它通过一个栈结构来管理应用中的页面。当一个新页面被打开时,它会被压入栈顶;当一个页面被关闭时,它会从栈顶弹出。通过对栈的操作,Navigator实现了页面间的跳转和导航。
Navigator 类是一个关键的组件,它提供了一系列方法来实现页面间的导航。通过路由直接跳转:
- push 栈顶入栈一个新的路由
- pushReplacement 将当前路由替换为一个新的路由
- pushAndRemoveUntil 根据参数决定栈内路由清除多少,并入栈一个新路由。
通过命名路由跳转:
- pushNamed 栈顶入栈一个新的路由
- pushReplacementNamed 将当前路由替换为一个新的路由
- pushNamedAndRemoveUntil 根据参数决定栈内路由清除多少,并入栈一个新路由
路由主动出栈:
- pop 当前路由出栈
- popAndPushNamed 当前路由出栈,入栈一个新路由
- popUntil 从栈顶开始,逐个pop,直到参数中指定的路由为止
- canPop 判断当前路由是否可以出栈,如果栈内只有当前路由,返回false,如果当前路由前面还有路由,返回true。也就是说栈底的路由,该方法返回false
- maybePop 当前路由如能能出栈就出栈,如果不能就什么都不做。
路由删除:
- removeRoute
- removeRouteBelow
路由替换:
- replace
- replaceRouteBelow
路由判断方法:
- of 获取当前context 的Navigator的实例.
- 几乎所有的Navigtor方法实现都是调用of后,再调用具体方法的,如pop:
static bool pop<T extends Object>(BuildContext context, [ T result ]) {
return Navigator.of(context).pop<T>(result);
}
静态路由
在编译时定义所有路由,并在需要导航时直接使用路由名称进行跳转
基本使用
在项目的 lib 目录下新建 routes 目录,新建 routes.dart 文件。
1. 首选需要引入,不然会报错。
import "package:flutter/material.dart";
2. 引入页面文件
arduino
代码解读
复制代码
import 'package:fushikang_flutter/pages/login_page.dart';
import 'package:fushikang_flutter/pages/index_page.dart';
3. 配置命名路由
ini
代码解读
复制代码
final routes = {
'/index': (context) => IndexPage(),
};
//固定写法
var onGenerateRoute = (RouteSettings settings) {
// 统一处理
final String name = settings.name;
final Function pageContentBuilder = routes[name];
final Route route = MaterialPageRoute(builder: (context) => pageContentBuilder(context));
return route;
};
'/index'是路由名称,这样我们的 routes.dart 文件就配置好了。
配置 main.dart
1. 我们回到 mian.dart 首先需要把routes文件引入到main中。
import 'routes/routes.dart';
2. 配置路由
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'test',
initialRoute: '/index', // 这是配置加载的第一个页面
onGenerateRoute: onGenerateRoute, // 重点看这里
);
}
}
3. 跳转页面
配置完成之后重新编译项目,在项目中调用以下代码就可以实现跳转页面了。
Navigator.pushNamed(context, '/index');
静态路由传参
1. 修改routes文件了。
final routes = {
// 传参
'/login': (context, {arguments}) => LoginPage(arguments: arguments),
// 不传参
'/index': (context) => IndexPage(),
};
//固定写法-路由传参
var onGenerateRoute = (RouteSettings settings) {
// 统一处理
final String name = settings.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;
}
}
};
2. 页面接受参数
某个页面需要传参,就需要在页面中这样写才能接收到参数,否则arguments就会是null
class LoginPage extends StatefulWidget {
final Map arguments;
LoginPage({Key key, this.arguments}) : super(key: key);
@override
_LoginPageState createState() => _LoginPageState(arguments: this.arguments);
}
class _LoginPageState extends State<LoginPage> {
Map arguments;
_LoginPageState({this.arguments});
...
}
3. 跳转页面并传参
以上都配置完成之后,重新编译项目在项目中调用以下代码就能实现路由传参。
Navigator.pushNamed(context, '/login', arguments: {"checkCode": 123456});
接受跳转返回的参数
A页面代码: 使用Navigator push一个新页面,pushNamed方法是有一个Future的返回值的,在then回调中监听并接收新页面回传回来的数据,并且借助showDialog显示在Dialog上
import 'package:flutter/material.dart';
import 'package:flutter_app/pages/simpleWidget/navigator/StaticNavigatorPageWithParams.dart';
void main() {
runApp(
new MaterialApp(home: new FlutterDemo(), routes: <String, WidgetBuilder>{
'router/new_page_with_callback': (_) => new StaticNavigatorPageWithResult()
}));
}
class FlutterDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Flutter进阶之旅"),
),
body: new Center(
child: new RaisedButton(
child: new Text("静态路由接收下一页返回值"),
onPressed: () {
Navigator.of(context)
.pushNamed('router/new_page_with_callback')
.then((value) {
showDialog(
context: context,
child: new AlertDialog(
content: new Text(value),
));
});
})),
);
}
}
B页面代码:
从效果图中可以看到,当我点击B页面中间的按钮时会把数据回传给上一页,但是直接点击导航栏左上角的返回按钮回到A页面时并不会把数据传递给上一个页面,这里是因为我在B页面的按钮上pop页面出栈的时候把参数放进里面作为了参数传递,pop()可接收一个Object对象作为参数传递
Navigator.of(context).pop(T extends Object);
这就告诉我们当我们需要给上一个页面回传数据的时候可直接借助pop传递Navigator.of(context).pop("页面结束后返回的数据");,不需要传值的时候直接返回空对象Navigator.of(context).pop()即可
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
配置路由守卫
前端开发过程中,页面跳转时会有路由守卫。而我们的flutter也有同样的功能。
1. 修改 routes 文件
在文件的最下方加入以下代码
//导航的观察者
//导航路由在跳转时的回调,比如 push,pop,remove,replace是,可以拿到当前路由和后面路由的信息
//继承NavigatorObserver
class NewObserver extends NavigatorObserver {
@override
void didPush(Route route, Route previousRoute) {
// 当调用Navigator.push时回调
super.didPush(route, previousRoute);
//可通过route.settings获取路由相关内容
print('跳转到下一个页面');
}
@override
void didPop(Route route, Route previousRoute) {
// 当调用Navigator.pop时回调
super.didPop(route, previousRoute);
print('跳回到上一个页面');
}
@override
void didRemove(Route route, Route previousRoute) {
// 当调用Navigator.Remove时回调
print('调用Navigator.Remove');
super.didRemove(route, previousRoute);
}
}
2. 配置路由守卫
回到 main.dart 主入口文件
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'test',
initialRoute: '/login',
onGenerateRoute: onGenerateRoute,
//导航的观察者
navigatorObservers: <NavigatorObserver>[NewObserver()],
);
}
}
动态路由
在Flutter中,动态路由是根据条件或用户操作来决定要导航到哪个页面,并可以通过传递参数来自定义每个页面。您可以使用Navigator.push方法和MaterialPageRoute来实现动态路由
- Navigator.push(context, MaterialPageRoute(builder: (context) => Screen()))导航到指定的页面组件。
- MaterialPageRoute(builder: (context) => Screen())创建一个新的页面路由。
- builder定义页面组件的构建函数。
- arguments传递给目标页面的参数。
跳转传值
//Home.dart
//只贴按钮的代码,其余的和上面一样
RaisedButton(
child: Text('跳到详情页面'),
onPressed: (){
//跳转页面
Navigator.of(context).push(
MaterialPageRoute(
//传值
builder: (context)=>Detail(Test:'我是参数')
//没传值
//builder: (context)=>Detail()
)
);
},
)
然后在目标页面接收,如果没传值默认为上面定义的默认值
Detail.dart文件代码:
class Detail extends StatelessWidget {
//需要定义变量和默认值
String Test;
Detail({this.Test='没有给我传值'});
@override
Widget build(BuildContext context) {
return Scaffold(
//浮动按钮
floatingActionButton: FloatingActionButton(
child: Text('返回'),
onPressed: (){
Navigator.of(context).pop();
},
),
appBar: AppBar(title: Text("详情页面"),),
body: Text(this.Test),
);
}
}