Navigator Helper2
文章目录
因为随着开发时间越来越长, 对于很多东西又有了新的理解, 是时候回头对于某些东西进行查漏补缺了
本篇就来补一补路由的东西
GlobalKey
这东西要单独说一说, 设置一下这东西, 你的 WidgetsApp 会把它设置给 Navigator, 这东西一旦设置成功, 后续就可以不用 Navigator.of, 拿到 NavigatorState 的实例了
然后这东西设置成全局的, 就可以在今后跳转的时候不用 context 了, 并且可以利用这个东西里的 context 来拿到全局的 Provider 类(这个不在本篇预计范围内)
设置:
1MaterialApp(
2 navigatorKey: navigatorKey,
3);
使用:
1NavigatorState get navigator => navigatorKey.currentState;
RouteHelper
全文如下, 但是有一个问题, 这个 navigatorKey 的 context 不能用于 showDialog, 所以需要自定义 dialog 的 route,才可以无 context 调用, 所以加了新的方法
同样的, 以前的 helper 中 push 才需要 context,pop 不需要考虑太多,所以没有 pop 方法, 现在因为有了全局 navigatorKey 来做路由, 所以添加了 pop 相关的方法
1import 'package:flutter/material.dart';
2
3import 'dialog_route.dart';
4
5class RouteHelper {
6 GlobalKey<NavigatorState> stateKey;
7
8 RouteHelper(this.stateKey);
9
10 NavigatorState get navigator => stateKey.currentState;
11
12 AnimUtils anim = AnimUtils();
13
14 Future<T> pushWidget<T>(
15 Widget widget, {
16 bool replaceRoot = false,
17 bool replaceCurrent = false,
18 dynamic replaceResult,
19 }) {
20 final materialRoute = MaterialPageRoute<T>(builder: (BuildContext context) {
21 return widget;
22 });
23 return pushRoute<T>(
24 materialRoute,
25 replaceRoot: replaceRoot,
26 replaceCurrent: replaceCurrent,
27 replaceResult: replaceResult,
28 );
29 }
30
31 Future<T> pushRoute<T>(
32 Route<T> newRoute, {
33 bool replaceRoot = false,
34 bool replaceCurrent = false,
35 dynamic replaceResult,
36 }) async {
37 assert(!(replaceCurrent && replaceRoot), "这两货只有一个可以为true");
38 if (replaceRoot) {
39 while (true) {
40 if (!(await navigator.maybePop())) {
41 break;
42 }
43 }
44 return navigator.pushReplacement<T, dynamic>(
45 newRoute,
46 result: replaceResult,
47 );
48 }
49 if (replaceCurrent) {
50 return navigator.pushReplacement<T, dynamic>(
51 newRoute,
52 result: replaceResult,
53 );
54 }
55 return navigator.push<T>(newRoute);
56 }
57
58 Future<T> showDialog<T>(
59 Widget dialog, {
60 TransitionsWidgetBuilder transitionsWidgetBuilder,
61 TransitionsWidgetBuilder pageBuilder,
62 Duration transitionsDuration = const Duration(milliseconds: 300),
63 }) {
64 // pageBuilder ??= anim.opacity;
65 pageBuilder ??= anim.empty;
66 transitionsWidgetBuilder ??= anim.opacity;
67 return pushRoute<T>(
68 DialogRoute<T>(
69 child: dialog,
70 pageBuilder: pageBuilder,
71 transitionsWidgetBuilder: transitionsWidgetBuilder,
72 transitionDuration: transitionsDuration,
73 ),
74 );
75 }
76
77 bool pop<T>([T result]) {
78 return navigator.pop(result);
79 }
80
81 Future<bool> maybePop<T>([T result]) async {
82 return navigator.maybePop(result);
83 }
84}
85
86class AnimUtils {
87 Widget opacity(BuildContext context, Animation<double> animation,
88 Animation<double> secondaryAnimation, Widget child) {
89 return AnimatedBuilder(
90 builder: (BuildContext context, Widget child) {
91 return Opacity(
92 opacity: animation.value,
93 child: child,
94 );
95 },
96 animation: animation,
97 child: child,
98 );
99 }
100
101 Widget empty(BuildContext context, Animation<double> animation,
102 Animation<double> secondaryAnimation, Widget child) {
103 return AnimatedBuilder(
104 builder: (BuildContext context, Widget child) {
105 return child;
106 },
107 animation: animation,
108 child: child,
109 );
110 }
111}
对应的一个关联类, 内部是 dialog 的 route 动画等东西,dialog_route.dart
1import 'package:flutter/material.dart';
2
3typedef Widget DialogWidgetBuilder(
4 BuildContext context,
5 Animation<double> animation,
6 Animation<double> secondaryAnimation,
7 Widget child,
8);
9
10typedef Widget TransitionsWidgetBuilder(
11 BuildContext context,
12 Animation<double> animation,
13 Animation<double> secondaryAnimation,
14 Widget child,
15);
16
17class DialogRoute<T> extends PopupRoute<T> {
18 final DialogWidgetBuilder pageBuilder;
19 final TransitionsWidgetBuilder transitionsWidgetBuilder;
20 final Duration transitionDuration;
21 final bool maintainState;
22 final bool barrierDismissible;
23 final Widget child;
24
25 DialogRoute({
26 this.pageBuilder,
27 this.maintainState = true,
28 this.transitionDuration = const Duration(milliseconds: 250),
29 this.barrierDismissible = true,
30 this.child,
31 this.transitionsWidgetBuilder,
32 }) : assert(!(pageBuilder == null && child == null));
33
34 @override
35 Color get barrierColor => Colors.black38;
36
37 @override
38 String get barrierLabel => "title";
39
40 @override
41 Widget buildPage(BuildContext context, Animation<double> animation,
42 Animation<double> secondaryAnimation) {
43 if (pageBuilder == null) {
44 return child;
45 }
46 return pageBuilder(context, animation, secondaryAnimation, child);
47 }
48
49 @override
50 Widget buildTransitions(BuildContext context, Animation<double> animation,
51 Animation<double> secondaryAnimation, Widget child) {
52 if (transitionsWidgetBuilder == null) {
53 return super
54 .buildTransitions(context, animation, secondaryAnimation, child);
55 }
56 return transitionsWidgetBuilder(
57 context, animation, secondaryAnimation, child);
58 }
59}
60
61mixin TransitionsMixin {
62 Widget buildTransitions(BuildContext context, Animation<double> animation,
63 Animation<double> secondaryAnimation, Widget child);
64
65 Duration transitionsDuration() => Duration(milliseconds: 300);
66}
67
68mixin TransitionsWidgetMixin on Widget, TransitionsMixin {}
69
70mixin TransitionsStateMixin on State, TransitionsMixin {}
BaseProvider
还有一篇不得不一起说的东西: 项目中所有提供者的基类, 这个类中会封装一些项目可能用到的东西, 以方便后续的状态的提供者继承以后拥有很多能力
1import 'package:flutter/material.dart';
2
3class BaseProvider extends ChangeNotifier {
4 static final navigatorKey = GlobalKey<NavigatorState>();
5
6 static RouteHelper _routeHelper = RouteHelper(navigatorKey);
7
8 final _notifiers = List<ChangeNotifier>();
9
10 final _autoDisposeList = List<ChangeNotifier>();
11
12 void bindChangeNotifier(
13 ChangeNotifier notifier, {
14 bool autoDispose = true,
15 }) {
16 if (autoDispose) {
17 _autoDisposeList.add(notifier);
18 }
19 notifier.addListener(notifyListeners);
20 _notifiers.add(notifier);
21 }
22
23 void bindChangeNotifiers(
24 List<ChangeNotifier> notifiers, {
25 bool autoDispose = true,
26 }) {
27 for (var notifier in notifiers) {
28 bindChangeNotifier(notifier, autoDispose: autoDispose);
29 }
30 }
31
32 void unbindChangeNotifier(ChangeNotifier notifier) {
33 notifier.removeListener(notifyListeners);
34 _notifiers.remove(notifier);
35 }
36
37 RouteHelper get routeHelper => _routeHelper;
38
39 NavigatorState get navigator => routeHelper.navigator;
40
41 @override
42 void dispose() {
43 for (final notifier in _notifiers.toList()) {
44 unbindChangeNotifier(notifier);
45 }
46 for (final notifier in _autoDisposeList) {
47 notifier.dispose();
48 }
49 super.dispose();
50 }
51}
这样就简单的将 RouteHelper 单例在了 provider 里, 在书写逻辑后直接就可以使用routeHelper.push(Widget())
来跳转页面
而 MaterialApp 中就可以设置BaseProvider.navigatorKey
到 navigatorKey 字段上
然后有一点需要说明, pop 方法在官方的中有修改, 返回值从 bool 变成了 void
请根据你自己的 flutter 版本修改返回值即可
后记
因为遇到了 pop 返回值和 dart-pad 上不一样的问题, 然后不小心把 dartpad 关了, 懒得再复制了, 所以没有完整代码说明, 以上