Flutter 一个简单的Route Helper/Navigator Helper
文章目录
在 flutter 中 route 是一个绕不开,必须面对,且很常用东西
Route 就是路由,顾名思义,负责你页面间的跳转
不想看代码和思路分析的直接 copy 了拿去用就行 没有啥外部依赖,只需要注意_rootRoute 后面的字符串需要和 initialRoute 对应即可
路由又分静态和动态路由
静态就是不需要传参数的,这样的路由可以直接定义在 MaterialApp/WidgetsApp 里
这样可以通过Navigator.pushNamed
调用
动态的就是传入一个PageRoute
, 通常是一个MaterialPageRoute
或者CupertinoPageRoute
,或者你如果有自定义的有可以使用
这里我使用一个我的工具类来实现跳转,因为大部分情况下,工程中的路由都是动态的,也就是需要传参数的,所以工具类中只包含了静态路由
1import 'dart:async';
2
3import 'package:flutter/material.dart';
4
5class RouteHelper {
6 static Future<T> pushWidget<T>(
7 BuildContext context,
8 Widget widget, {
9 bool replaceRoot = false,
10 bool replaceCurrent = false,
11 }) {
12 return pushRoute(
13 context,
14 MaterialPageRoute(builder: (ctx) => widget),
15 replaceRoot: replaceRoot,
16 replaceCurrent: replaceCurrent,
17 );
18 }
19
20 static Future<T> pushRoute<T>(
21 BuildContext context,
22 PageRoute<T> route, {
23 bool replaceRoot = false,
24 bool replaceCurrent = false,
25 }) {
26 assert(!(replaceRoot == true && replaceCurrent == true));
27 if (replaceRoot == true) {
28 return Navigator.pushAndRemoveUntil(
29 context,
30 route,
31 _rootRoute,
32 );
33 }
34 if (replaceCurrent == true) {
35 return Navigator.pushReplacement(context, route);
36 }
37 return Navigator.push(context, route);
38 }
39}
40
41var _rootRoute = ModalRoute.withName("home");
解析一下这个类,有两个方法,一个是接受 PageRoute,一个是接收 Widget
接收 Widget 的是讲 Widget 包装为 MaterialPageRoute,然后传给另一个方法
另一个方法中包含 3 种情况,一种是替换根节点,一种是替换当前页面(关闭当前,且开启新页面),还有一种就是平常的 push(即 不关闭当前,直接开启新的)
根据传参不同而有所不同
有一个_rootRoute
变量,这个变量的目的是用于替换根节点,'home'
是我定义在MaterialApp
里的initialRoute
,这样一一对应才能确保替换根节点
当然这个类也可以继续扩展,比如将 routes 定义在内,然后传 route name 参数,接着通过 routes 来提取出 named 对应的 Widget/Route 接着传入pushRoute
方法进行跳转即可
这个简便的 Helper 还有另一个好处,就是可以方便后续批量替换 Route 实现,比如有一天你想自定义一个 PageRoute,不使用 MaterialRoute ,那么你只需要替换如下如所示的部分即可
当然还可以有别的扩展方法来支持named
比如查看Navigator
的源码发现pushNamed
,就是通过widget.onGenerateRoute
方法获取到route
的,我这里直接在 helper 中写就好了
Helper 写完了,我们看看使用的方法 使用起来也很简单
比如强登陆应用
1 void _login() {
2 RouteHelper.pushWidget(context, HomeRootPage(), replaceRoot: true);
3 }
这里登录成功后,我直接替换了 root 节点,然后根路由就变成了主页面
1 void _forgetPwd() {
2 RouteHelper.pushWidget(context, ForgetPwdPage());
3 }
4
5 void _register() {
6 RouteHelper.pushWidget(context, RegiseterPage());
7 }
忘记密码和注册都基于登录在做,最终要返回登录,所以这里用普通的调用方法
1 _register() {
2 RouteHelper.pushWidget(
3 context,
4 RegisterSuccessPage(),
5 replaceCurrent: true,
6 );
7 }
注册成功后我这里有一个单独的注册成功页,写了一些注册后的注意事项,而返回又应该直接返回到登录页面,所以这里我需要替换掉当前的页面,只用 replaceCurrent 即可
当然方法接受返回值也是允许的
1
2 _orderDetail(String item) async {
3 //todo 查看订单详情
4 var result = await RouteHelper.pushWidget<bool>(context, OrderDetailPage(id: item));
5 if (result == true) {
6 _refresh();
7 }
8 }
这里如果在详情页买了东西/加到购物车,回到主页面,是要刷新页面的,所以我们接收返回值,然后判断
小 tips:这里之所以用 result == true 而不是 if(result) 是因为 dart 中 bool
是有 3 个值的 true false null
if(result==true)
可以将 result 为 null 的情况规避掉,提升代码健壮性,这个不得不说是 dart 完全面向对象造成的副作用
补:在这之后有朋友发出了他的代码运行结果,显示这个在他那里没有问题,我这里出现这个问题是 dart 的正式发布版 2.0.0/2.1.0 出现的 flutter 中自带的 dart sdk 也会出现这样的问题