前言
页面跳转:
1、Android初始化 Intent通过 startActivity打开新页面
2、iOS初始化ViewController通过pushViewController 打开新页面
3、Rect navigation管理页面
Flutter 则借鉴上面两种类型
Flutter路由导航
在 Flutter 中,页面之间的跳转是通过 Route 和 Navigator 来管理的:
Route 是页面的抽象,主要负责创建对应的界面,接收参数,响应 Navigator 打开和关闭;
而 Navigator 则会维护一个路由栈管理 Route,Route 打开即入栈,Route 关闭即出栈,还可以直接替换栈内的某一个 Route。
而根据是否需要提前注册页面标识符,Flutter 中的路由管理可以分为两种方式:
1、基本路由。无需提前注册,在页面切换时需要自己构造页面实例。
2、命名路由。需要提前注册页面标识符,在页面切换时通过标识符直接打开新的路由。
基本路由:就是最原始的跳转方式
在 Flutter 中,基本路由的使用方法和 Android/iOS 打开新页面的方式非常相似
要导航到一个新的页面,我们需要创建一个MaterialPageRoute的实例,调用 Navigator.push 方法将新页面压到堆栈的顶部。其中,MaterialPageRoute 是一种路由模板,定义了路由创建及切换过渡动画的相关配置,可以针对不同平台,实现与平台页面切换动画风格一致的路由切换动画。而如果我们想返回上一个页面,则需要调用 Navigator.pop 方法从堆栈中删除这个页面。
RaisedButton(
child: Text('基本路由'),
onPressed: () => Navigator.push(context,
MaterialPageRoute(builder: (context) => SecondPage()))),
RaisedButton(
child: Text('back'),
onPressed: ()=> Navigator.pop(context,"Hi")
命名路由
每次跳转需要手动创建MaterialPageRoute 实例,初始化,然后push。
命名路由通过给页面起一个名字,通过页面名字打开即可。
要想通过名字来指定页面切换,我们必须先给应用程序 MaterialApp 提供一个页面名称映射规则,即路由表routes,这样 Flutter 才知道名字与页面 Widget 的对应关系。路由表实际上是一个Map,其中key 值对应页面名字,而 value 值则是一个 WidgetBuilder 回调函数,我们需要在这个函数中创建对应的页面。
而一旦在路由表中定义好了页面名字,我们就可以使用 Navigator.pushNamed 来打开页面了。
在注册路由表时,Flutter 提供了 UnknownRoute 属性,我们可以对未知的路由标识符进行统一的页面跳转处理。
/// 路由管理工具类
class RouterManager {
/// 路由映射表 - 页面名称与页面构建器的对应关系
static final Map<String, WidgetBuilder> _routes = {
// 首页
'/router': (context) => RouterTestPage(),
'/second_page':(context)=>SecondPage(),
'/third_page':(context)=>ThirdPage()
// // 示例页面1
// '/example1': (context) => const ExamplePage1(),
// // 示例页面2(带参数)
// '/example2': (context) => const ExamplePage2(),
// 可以继续添加更多页面...
};
/// 路由观察者 - 用于监听路由变化
static final RouteObserver<ModalRoute> routeObserver = RouteObserver<ModalRoute>();
/// 生成路由
static Route<dynamic> generateRoute(RouteSettings settings) {
final String? name = settings.name;
final Function? pageBuilder = _routes[name];
// 路由拦截逻辑 - 可在此处添加登录验证等全局拦截
/*
if (_needLoginIntercept(name)) {
// 如果需要登录但未登录,跳转到登录页
return MaterialPageRoute(
builder: (context) => const LoginPage(),
settings: const RouteSettings(name: '/login'),
);
}
*/
if (pageBuilder != null) {
// 修正:只传递 context,不传递额外参数
return MaterialPageRoute(
builder: (context) => pageBuilder(context), // 仅传 context
settings: settings, // 保留 settings 以存储参数
);
}
// 未找到对应路由时返回404页面
return MaterialPageRoute(
builder: (context) => NotFoundPage(routeName: name),
);
}
跳转:
RouterManager.push(context, '/second_page'))
demo中罗列了 基础路由 命名路由传参的情形
import 'package:flutter/material.dart';
import './routerManager.dart';
class RouterTestPage extends StatefulWidget {
@override
State<StatefulWidget> createState() => _routerPageState();
}
class _routerPageState extends State<RouterTestPage> {
String? _msg;
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('First Screen'),
),
body: Column(
children: <Widget>[
RaisedButton(
child: Text('基本路由'),
onPressed: () => Navigator.push(context,
MaterialPageRoute(builder: (context) => SecondPage()))),
RaisedButton(
child: Text('命名路由'),
// onPressed: ()=> Navigator.pushNamed(context,"/second_page")
onPressed: () => RouterManager.push(context, '/second_page')),
RaisedButton(
child: Text('命名路由(参数&回调)'),
onPressed: () => RouterManager.push(
context,
'/third_page',
arguments: "Hey",
).then((msg) {
setState(() {
_msg = (msg ?? "啦啦啦") as String?;
});
}),
),
//
// onPressed: ()=> Navigator.pushNamed(context, "/third_page",arguments: "Hey").then((msg) {
// setState(() {
// _msg = (msg ?? "啦啦啦") as String?;
// });
// }),
// ),
Text('Message from Second screen: $_msg'),
RaisedButton(
child: Text('命名路由异常处理'),
onPressed: () => Navigator.pushNamed(context, "unknown_page"))
],
),
);
}
}
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Second Screen'),
),
body: RaisedButton(
child: Text('Back to first screen'),
onPressed: () => RouterManager.pop(context),
));
}
}
class ThirdPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
// String msg = ModalRoute.of(context)!.settings.arguments as String;
// final Map? args = RouterManager.getArguments<Map>(context);
final String? args = RouterManager.getArguments<String>(context);
return Scaffold(
appBar: AppBar(
title: Text('Third Screen'),
),
body: Column(
children: <Widget>[
Text('Message from first screen: ${args ?? "无参数"}'),
// Text('Message from first screen: $msg'),
RaisedButton(
child: Text('back'),
onPressed: () => RouterManager.pop(context,result: '我返回啦'))
//onPressed: ()=> Navigator.pop(context,"Hi")
],
),
);
}
}