深色模式
Flutter 监听路由变化
原理
在MaterialApp()
中有一个navigatorObservers
参数,可以监听全局的路由变化。
常规使用
创建observer
dart
RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>();
注册observer
dart
MaterialApp(
navigatorObservers: [routeObserver],
// ...
)
在需要监听的页面使用observer,需要订阅、取消订阅、实现4个回调方法。
dart
class ARouteObserverDemo extends StatefulWidget {
@override
_RouteObserverDemoState createState() => _RouteObserverDemoState();
}
class _RouteObserverDemoState extends State<ARouteObserverDemo> with RouteAware {
@override
void didChangeDependencies() {
super.didChangeDependencies();
routeObserver.subscribe(this, ModalRoute.of(context));
}
@override
void dispose() {
super.dispose();
routeObserver.unsubscribe(this);
}
@override
void didPush() {
final route = ModalRoute.of(context).settings.name;
print('A-didPush route: $route');
}
@override
void didPopNext() {
final route = ModalRoute.of(context).settings.name;
print('A-didPopNext route: $route');
}
@override
void didPushNext() {
final route = ModalRoute.of(context).settings.name;
print('A-didPushNext route: $route');
}
@override
void didPop() {
final route = ModalRoute.of(context).settings.name;
print('A-didPop route: $route');
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
alignment: Alignment.center,
child: RaisedButton(
child: Text('A RouteObserver'),
onPressed: () {
Navigator.of(context).pushNamed('/BRouteObserver');
},
),
),
);
}
}
关键在于4个回调方法,在RouteAware
中,对4个回调方法有注释说明:
dart
/// Called when the top route has been popped off, and the current route shows up.
void didPopNext() { }
/// Called when the current route has been pushed.
void didPush() { }
/// Called when the current route has been popped off.
void didPop() { }
/// Called when a new route has been pushed, and the current route is no longer visible.
void didPushNext() { }
假设我们观察的页面是A,那么:
didPopNext()
: A上面的页面已弹出,此时A可见。didPush()
: A页面入栈didPop()
: A页面出栈didPushNext()
: 另一页面入栈,A不可见
使用hook
TIP
如果项目中使用了flutter_hooks,自然而然就会想到此方法。
按照上面的使用方式,需要订阅、取消订阅、实现4个回调方法,样板代码太多了,一个简单的方式是使用hook。
定义一个hook名为useRouteObserver
:
(目前flutter_hooks库并没有收录此hook,可以自行copy代码)
dart
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
class _RouteCallbacks with RouteAware {
const _RouteCallbacks({
this.handleDidPopNext,
this.handleDidPush,
this.handleDidPop,
this.handleDidPushNext,
});
final VoidCallback? handleDidPopNext;
final VoidCallback? handleDidPush;
final VoidCallback? handleDidPop;
final VoidCallback? handleDidPushNext;
@override
void didPopNext() {
handleDidPopNext?.call();
}
@override
void didPush() {
handleDidPush?.call();
}
@override
void didPop() {
handleDidPop?.call();
}
@override
void didPushNext() {
handleDidPushNext?.call();
}
}
void useRouteObserver(
RouteObserver<ModalRoute> routeObserver, {
VoidCallback? didPopNext,
VoidCallback? didPush,
VoidCallback? didPop,
VoidCallback? didPushNext,
List<Object?> keys = const [],
}) {
final context = useContext();
final route = ModalRoute.of(context);
useEffect(() {
if (route == null) return () {};
final callbacks = _RouteCallbacks(
handleDidPop: didPop,
handleDidPopNext: didPopNext,
handleDidPush: didPush,
handleDidPushNext: didPushNext,
);
routeObserver.subscribe(callbacks, route);
return () => routeObserver.unsubscribe(callbacks);
}, [route, routeObserver, ...keys]);
}
在要观察的页面使用此hook,不需要的回调可以不传
dart
@override
Widget build(BuildContext context) {
useRouteObserver(
routeObserver,
didPush: () => refreshUserInfo(),
didPopNext: () => refreshUserInfo(),
// didPushNext: () {},
// didPop: () {},
);
}