赞
踩
Navigator 2.0 提供了一系列全新接口,可以实现将路由状态成为应用状态的一部分,新增的 API 如下:
Page :表示 Navigator 路由栈中各个页面的不可变对象;Page 是个抽象类,通常使用他的派生类: MaterialPage 或 CupertinoPage;
Router:用来配置要由 Navigator 展示的页面列表,通常改页面列表会根据系统的状态而改变;除了使用 Router 本身还可以使用 MaterialApp.router()来创建 Router;
RouterDelegate:定义程序中的路由行为,如 Router 如何知道应用程序状态变化以及如何响应;主要工作监听 RouterInformationParser 和应用状态,并使用当前列表构建 Pages;
还有另外几个不常用的:RouterInformationParser、RouterInformationProvider 和 BackButtonDispatcher ,可自行百度了解。
大概流程图如下:
当 app 打开进入 RouterDelegate 中的 build 方法,在里面手动创建堆栈,将要显示的页面放入到堆栈,然后走 setNewRoutePath 方法,然后再重新 build。当我们手动进入新的页面后,再次执行RouterDelegate 中的 build 方法。返回到上一页面会调用 onPopPage 方法。
这个思想和 Android 的是一样的,在 Android 中,也会创建堆栈,将要显示的页面放到里面,如果要显示已经存在的页面,将其它页面出栈然后显示出来。不过堆栈和页面跳转是分开的。
不过 flutter 中的 Navigator 2.0 将堆栈和路由导航封装到了一起,所以看起来十分麻烦,但是利于后面的项目维护。
这是封装后的效果:
大概的思路是在 RouterDelegate 中的 build 方法中,创建了堆栈,如果页面已经存在,则将该页面和上面的页面进行出栈,然后新建改页面放入堆栈中,如果该页面不存在,那么新建页面放入栈中。
CSDN 下载源码:https://download.csdn.net/download/wuqingsen1/53386218
GitHub 下载源码:GitHub - wuqingsen/FlutterLearnDemo: flutter学习记录
主要代码:
my_navigator.dart ,主要工具类,创建页面,路由状态,监听跳转等:
- import 'package:flutter/material.dart';
- import 'package:flutter_blbl/page/home_page.dart';
- import 'package:flutter_blbl/page/login_page.dart';
- import 'package:flutter_blbl/page/registration_page.dart';
- import 'package:flutter_blbl/page/video_detail_page.dart';
-
- typedef RouteChangeListener(RouteStatusInfo current, RouteStatusInfo pre);
-
- ///创建页面
- pageWrap(Widget child) {
- return MaterialPage(key: ValueKey(child.hashCode), child: child);
- }
-
- ///获取routeStatus在页面栈中的位置,
- int getPageIndex(List<MaterialPage> pages, RouteStatus routeStatus) {
- for (int i = 0; i < pages.length; i++) {
- MaterialPage page = pages[i];
- if (getStatus(page) == routeStatus) {
- return i;
- }
- }
- return -1;
- }
-
- ///路由封装,路由状态
- enum RouteStatus { login, registration, home, detail, unknown }
-
- ///获取page对应的routeStatus
- RouteStatus getStatus(MaterialPage page) {
- if (page.child is LoginPage) {
- return RouteStatus.login;
- } else if (page.child is RegistrationPage) {
- return RouteStatus.registration;
- } else if (page.child is HomePage) {
- return RouteStatus.home;
- } else if (page.child is VideoDetailPage) {
- return RouteStatus.detail;
- } else {
- return RouteStatus.unknown;
- }
- }
-
- ///路由信息
- class RouteStatusInfo {
- final RouteStatus routeStatus;
- final Widget page;
-
- RouteStatusInfo(this.routeStatus, this.page);
- }
-
- class MyNavigator extends _RouteJumpListener {
- static MyNavigator _instance;
-
- RouteJumpListener _routeJump;
-
- List<RouteChangeListener> _listeners = [];
- RouteStatusInfo _current; //打开过的页面
- MyNavigator._();
-
- ///注册路由跳转逻辑
- void registerRouteJump(RouteJumpListener routeJumpListener) {
- this._routeJump = routeJumpListener;
- }
-
- ///监听路由页面跳转
- void addListener(RouteChangeListener listener) {
- if (!_listeners.contains(listener)) {
- _listeners.add(listener);
- }
- }
-
- ///移除监听
- void removeListener(RouteChangeListener listener) {
- _listeners.remove(listener);
- }
-
- @override
- void onJumpTo(RouteStatus routeStatus, {Map args}) {
- _routeJump.onJumpTo(routeStatus, args: args);
- }
-
- ///通知路由页面变化,currentPages当前页面,prePages上一次页面
- void notify(List<MaterialPage> currentPages, List<MaterialPage> prePages) {
- //路由堆栈无变化不处理
- if (currentPages == prePages) return;
- var current =
- RouteStatusInfo(getStatus(currentPages.last), currentPages.last.child);
- _notify(current);
- }
-
- void _notify(RouteStatusInfo current) {
- print('my_navigator:current:' + current.page.toString());
- print('my_navigator:pre:' + _current?.page.toString());
- _listeners.forEach((listener) {
- listener(current, _current);
- });
- _current = current;
- }
-
- static MyNavigator getInstance() {
- if (_instance == null) {
- _instance = MyNavigator._();
- }
- return _instance;
- }
- }
-
- abstract class _RouteJumpListener {
- void onJumpTo(RouteStatus routeStatus, {Map args});
- }
-
- typedef OnJumpTo = void Function(RouteStatus routeStatus, {Map args});
-
- ///定义路由跳转逻辑要实现功能
- class RouteJumpListener {
- final OnJumpTo onJumpTo;
-
- RouteJumpListener({this.onJumpTo});
- }

main.dart :
- import 'package:data_plugin/bmob/bmob.dart';
- import 'package:flutter/material.dart';
- import 'package:data_plugin/data_plugin.dart';
- import 'package:flutter_blbl/db/hi_cache.dart';
- import 'package:flutter_blbl/model/navigator/my_navigator.dart';
- import 'package:flutter_blbl/model/video_model.dart';
- import 'package:flutter_blbl/page/home_page.dart';
- import 'package:flutter_blbl/page/login_page.dart';
- import 'package:flutter_blbl/page/registration_page.dart';
- import 'package:flutter_blbl/page/video_detail_page.dart';
- import 'package:flutter_blbl/utils/Constants.dart';
- import 'package:flutter_blbl/utils/color.dart';
- import 'package:permission_handler/permission_handler.dart';
- import 'package:shared_preferences/shared_preferences.dart';
-
- import 'db/PersistentStorage.dart';
- import 'db/my_shared_preferences.dart';
- import 'utils/toast.dart';
-
- void main() {
- SharedPreferences.setMockInitialValues({});
- runApp(const MyApp());
- }
-
- class MyApp extends StatelessWidget {
- // This widget is the root of your application.
- const MyApp({Key key}) : super(key: key);
-
- @override
- Widget build(BuildContext context) {
- return MaterialApp(title: 'An App', home: LoadingPage());
- }
- }
-
- class LoadingPage extends StatefulWidget {
- const LoadingPage({Key key}) : super(key: key);
-
- @override
- _MyAppState createState() => _MyAppState();
- }
-
- class _MyAppState extends State<LoadingPage> {
- BiliRouteDelegate _routeDelegate = BiliRouteDelegate();
-
- // Future<dynamic> fetchName() async {
- // SharedPreferences pf = await SharedPreferences.getInstance();
- // String response1 = pf.getString(SPName);
- // String response = await PersistentStorage().getStorage(SPName);
- // userName = response;
- // print('姓名' + response + "," + userName + response1);
- // return response;
- // }
-
- @override
- void initState() {
- Bmob.initMasterKey(
- "https://api2.bmob.cn",
- "bdb1a27490a65408db30a862b5023ffa",
- "1ef17ded7609019652b448773b06e1bd",
- "574fb1ffbe28cce59414d678d1817eca");
- super.initState();
- }
-
- @override
- Widget build(BuildContext context) {
- var widget = Router(
- //定义route
- routerDelegate: _routeDelegate,
- );
- return MaterialApp(
- home: widget,
- theme: ThemeData(primarySwatch: white),
- );
-
- //如果要请求网络或初始化数据可以调用下面
- // return FutureBuilder<dynamic>(
- // //进行初始化
- // future: fetchName(),
- // builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
- // //加载完成显示页面,否则显示加载中
- // print("加载状态:" + snapshot.toString());
- // var widget;
- // if (snapshot.connectionState == ConnectionState.done) {
- // widget = Router(
- // //定义route
- // routerDelegate: _routeDelegate,
- // );
- // }
- // return MaterialApp(
- // home: widget,
- // theme: ThemeData(primarySwatch: white),
- // );
- // });
- }
- }
-
- ///路由代理
- class BiliRouteDelegate extends RouterDelegate
- with ChangeNotifier, PopNavigatorRouterDelegateMixin {
- final GlobalKey<NavigatorState> navigatorKey;
-
- //默认进入首页
- RouteStatus _routeStatus = RouteStatus.home;
-
- BiliRouteDelegate() : navigatorKey = GlobalKey<NavigatorState>() {
- //实现跳转逻辑
- MyNavigator.getInstance().registerRouteJump(
- RouteJumpListener(onJumpTo: (RouteStatus routeStatus, {Map args}) {
- _routeStatus = routeStatus;
- //主页会往详情页传值
- if (routeStatus == RouteStatus.detail) {
- this.videoModel = args['videoMo'];
- }
- notifyListeners();
- }));
- }
- List<MaterialPage> pages = []; //存放所有页面的列表
- VideoModel videoModel;
-
- @override
- Widget build(BuildContext context) {
- var index = getPageIndex(pages, routeStatus);
- List<MaterialPage> tempPages = pages;
- //如果需要打开的页面已经存在,改页面和上面的页面进行出栈
- if (index != -1) {
- tempPages = tempPages.sublist(0, index);
- }
- var page;
- print('routeStatus:' + routeStatus.toString());
- if (routeStatus == RouteStatus.home) {
- //跳转到首页,将其它页面都出栈,然后创建新的首页
- pages.clear();
- page = pageWrap(HomePage());
- } else if (routeStatus == RouteStatus.detail) {
- //打开详情页
- page = pageWrap(VideoDetailPage(videoModel));
- } else if (routeStatus == RouteStatus.registration) {
- //打开注册页面
- page = pageWrap(RegistrationPage());
- } else if (routeStatus == RouteStatus.login) {
- page = pageWrap(LoginPage());
- }
-
- //重新创建堆栈数组
- tempPages = [...tempPages, page];
- pages = tempPages;
- //通知路由发生变化
- MyNavigator.getInstance().notify(tempPages, pages);
- return WillPopScope(
- child: Navigator(
- key: navigatorKey,
- pages: pages,
- onPopPage: (route, result) {
- if (route.settings is MaterialPage) {
- if ((route.settings as MaterialPage).child is LoginPage) {
- //
- }
- }
- //在这里控制是否可以返回上一页
- if (!route.didPop(result)) {
- return false;
- }
- var temPages = [...pages];
- pages.removeLast();
- //通知路由变化
- MyNavigator.getInstance().notify(pages, temPages);
- return true;
- },
- ),
- //手机返回键返回到上一页
- onWillPop: () async => !await navigatorKey.currentState.maybePop());
- }
-
- RouteStatus get routeStatus {
- //返回要进入的页面,登录或主页等
- if (_routeStatus != RouteStatus.registration && USERNAME == null) {
- return _routeStatus = RouteStatus.login;
- } else if (videoModel != null) {
- return _routeStatus = RouteStatus.detail;
- } else {
- return _routeStatus;
- }
- }
-
- @override
- Future<void> setNewRoutePath(configuration) {}
- }

页面跳转:
- //不传值
- MyNavigator.getInstance().onJumpTo(RouteStatus.registration);
-
- //传值
- MyNavigator.getInstance().onJumpTo(RouteStatus.detail,
- args: {'videoMo': VideoModel(1212)});
====== 扩展
flutter 中无法监听 Android 原生的 onResume 和 onPause 方法,在里面也封装了如何监听 onResume 和 onPause :
- var listener;
- @override
- void initState() {
- super.initState();
- MyNavigator.getInstance().addListener((current, pre) {
- print('current:' + current.page.toString());
- print('current:' + pre.page.toString());
- if (widget == current.page || current.page is HomePage) {
- print('打开了首页:onResume');
- } else if (widget == pre?.page || pre?.page is HomePage) {
- print('首页:onPause');
- }
- });
- }
-
- @override
- void dispose() {
- MyNavigator.getInstance().removeListener(this.listener);
- super.dispose();
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。