Flutter Navigator 2.0 路由管理

3,994 阅读4分钟

为什么要用Navigator 2.0

  • 1.0 API 中的 initialRoute 参数,即系统默认的初始页面,在应用运行后就不能再更改了
  • 1.0的命令式 Navigator API 只提供给了开发者一些非常针对性的接口,如 push()pop() 等,而没有给出一种更灵活的方式让我们直接操作路由栈
  • 1.0嵌套路由下,手机设备自带的回退按钮只能由根 Navigator 响应

路由管理插件(navigator_manager )的诞生

由于Navigator2.0的新增Api对于新手有一些学习成本,所以封装了一套开箱即用的路由管理插件。 需要解决的问题:

1.如何管理路由

RouterDelegate是2.0的路由代理,需要靠它来管理Router。首先我们先要理解下Navigator 2.0的路由原理。 enter image description here 如上图所示:当用户点击按钮跳转页面时,改变的是整个应用的路由栈状态,通知给Router,更新Navigator,从而更新子组件。而每一个子组件是就是一个Route,由我们配置的Page生成。这一点与Widget和Element的关系是相似的。

enter image description here

Navigator2.0的原理明白后,可以看出最核心的部分就是管理Router,需要设计RouterDelegate如下: image.png 其中RouteManager模块是一个Provider,通过内部封装的跳转方法来操作uris(路由uri)和pages(页面栈)去通知Navigator进行更新,从而实现页面跳转。

2. 如何进行路由跳转和传参

由于Flutter对web的支持越来越完善,所以路由跳转传参也需要支持两种应用场景:

  • web(路由可见、有刷新页面功能)
  • app(路由不可见、无刷新页面功能)

针对两种场景下的特点: web:推荐使用uri方式进行传参。

    1. 路由参数可见(?a=1&b=2)
    1. 刷新页面不会丢失参数

app:推荐使用params方式进行传参。

    1. 支持自定义参数类型(传对象)
    1. 读取路由参数更灵活

跳转方法是统一的、语义化的: 跳转

go(Uri uri, {dynamic params})

替换

replace(Uri uri, {dynamic params})

返回

goBack()

回到首页并清空路由栈

goRoot()

清空路由栈并跳到指定页面

clearAndGo(Uri uri, {dynamic params})

添加多个页面栈(并跳到最后一个)

multipleGo(List<Uri> uris, {List<dynamic> params})

等待页面结果并跳转,配合returnResultGo使用

waitResultGo(Uri uri, {dynamic params})

页面返回结果,支持异步

returnResultGo(dynamic value)

更多方法可以去看文档

3. 如何进行路由监听

为什么要有路由监听?举个🌰 : ** 抖音主页跳转到个人主页时需要暂停视频播放,从个人主页返回时需要再次播放视频。 ** 这个功能怎么做?需要注意以下两点

  • ios的右滑退出,会触发pop
  • 路由跳转后上一个页面并不会执行release,所以无法在release里控制播放

恶心的实现: 在没有路由监听的功能时,我们会在点击跳转事件里进行控制,需要点击个人主页跳转时暂停视频播放,在点击个人主页返回时播放视频。如果又新增其他跳转逻辑,要一样添加播放暂停逻辑,很麻烦也很容易出错。而且个人主页点进去也是播放视频详情,又要进行播放控制。所以一旦产生bug,解决起来会让你十分头大。而且ios右滑退出还要自己做手势监听去处理。

路由有了监听方法: 目前有两种监听方式:全局模式和页面模式。

  • 全局模式是全局监听路由栈的变化:
_routerDelegate.addListener(() {     print(_routerDelegate.currentConfiguration)
})
  • 页面模式是页面的push和pop的钩子函数:
/// 当上个页面退出且该页面显示时
@override
void didPopNext() { }

/// 该页面进入时
@override
void didPush() { }

/// 该页面退出时
@override
void didPop() { }

/// 当新页面进入且当前页面不在显示时
@override
void didPushNext() { }

有了路由监听,我们就可以在钩子函数里针对当前页面进行逻辑处理(播放、暂停),对路由的变化做了统一的监听,十分方便易维护。

navigator_manager使用教程

第一步:在应用顶层main.dart注册LRouterDelegate

import 'package:navigator_manager/navigator_manager.dart';
final RouterDelegate _routerDelegate = LRouterDelegate(
    /// 配置所有路由信息
    routes: {
      '/': (_, __) => HomePage(),
      '/login': (uri, _) => LoginPage(uri.queryParameters['id']),
      '/personal': (_, params) => PersonalPage(params),
    },
  );
MaterialApp.router(
    title: BasicConfig.APPName,    
    routeInformationParser: LRouteInformationParser(),
    routerDelegate: _routerDelegate,
),

your page

class PersonalPageParams {
  final UserInfo userInfo;
  PersonalPageParams(this.userInfo);
}

class PersonalPage extends Page {
  final PersonalPageParams params;
  PersonalPage(this.params) : super(key: ValueKey('personal-page'));

  @override
  Route createRoute(BuildContext context) {
    return MaterialPageRoute(
      settings: this,
      builder: (BuildContext context) {
        return _PersonalPageWidget(params);
      },
    );
  }
}

第二步:调用方法

RouteManager.of(context).go(Uri(path: '/test/todo', queryParameters: {'text': '12'}));
					
RouteManager.of(context).go(Uri(path: '/login'), params: UserInfo(name: 'your name', age: 18));

第三步:监听路由

监听全局路由信息
_routerDelegate.addListener(() {
  if (_routerDelegate.currentConfiguration == Uri(path: '/')) {
    /// to do
  }
}

or

在页面监听钩子函数
class APage extends StatefulWidget {
  const APage({Key key}) : super(key: key);

  @override
  _APageState createState() => _APageState();
}

// 3. Add `with RouteAware, RouteObserverMixin` to State and override RouteAware methods.
class _APageState extends State<APage> with RouteAware, RouteObserverMixin {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Text('A Page'),
        ),
      ),
    );
  }

  @override
  void didPopNext() { }

  @override
  void didPush() { }

  @override
  void didPop() { }

  @override
  void didPushNext() { }
}

至此,你的项目就有了路由管理功能,该插件使用简单,功能强大,欢迎使用!