2020.10.20日更新:
最近发现了一种更好的方法,就是使用RouteAware监听路由,下面是实现代码
初始化:
RouteObserver需要申明为全局属性并作为参数传入MaterialApp中
static final RouteObserver<PageRoute> routeObserver = RouteObserver();
@override
Widget build(BuildContext context) {
return MaterialApp(
navigatorObservers: [AppRoutesManager.routeObserver],
...
);
}
使用
abstract class BaseState<T extends StatefulWidget, E extends BaseViewModel> extends State<T> with RouteAware {
String pageName;
E viewModel;
void initState() {
super.initState();
}
@override
void didChangeDependencies() {
AppRoutesManager.routeObserver.subscribe(this, ModalRoute.of(context)); //订阅
super.didChangeDependencies();
print("didChangeDependencies: ${pageName}界面");
}
@override
void didPush() {
debugPrint("------> didPush-进入${pageName}");
super.didPush();
}
@override
void didPop() {
debugPrint("------> didPop离开${pageName}");
super.didPop();
}
@override
void didPopNext() {
debugPrint("------> didPopNext-进入${pageName}");
super.didPopNext();
}
@override
void didPushNext() {
debugPrint("------> didPushNext-${pageName}进入下一个界面");
super.didPushNext();
}
@override
void dispose() {
AppRoutesManager.routeObserver.unsubscribe(this); //取消订阅
super.dispose();
// print("dispose 离开${pageName}界面");
print("销毁${pageName}界面");
}
但是这个方法有一定的缺陷:
1,AlertView,showGeneralDialog等弹出框里面push的路由没有办法监听,我的解决办法是是写一个回调函数来让主界面来处理路由的push;
2,当使用PageView做界面切换时,监听也是不生效的,这个时候需要自己手动调用RouteAware里面的函数。
下面是之前的实现方法:
之前项目集成了友盟统计的功能,发现flutter界面统计无法实现,在iOS中我们可以通过Controller的生命周期中的viewWillAppear:来处理什么时候进入界面viewWillDisappear:来处理什么时候来开界面,离开界面的处理,flutter的组件虽然也有生命周期,但是它的生命周期不足以支持我们准确的统计,虽然我们可以用initState做进入的的逻辑,用dispose做离开的逻辑,但是initState 只有在组件第一次初始化的时候跳用,dispose只有在组件销毁的时候才会调用;当我们使用Navigator.push离开当前界面进入下一个界面时我们没有办法做处理,当然我们也可以选择在每一个push的地方做处理,但是这样就会出现大量的重复代码,显然不符合我们的初衷,经过思考我给出了下面这个方案:
1,写一个基类BaseState继承自State,其中有一个参数pageName
abstract class BaseState<T extends StatefulWidget> extends State {
String pageName;
void initState() {
// TODO: implement initState
super.initState();
print("initState 进入${pageName}界面");
FlutterBlUmpushPlugin.umengEnterViewWithName(pageName);
}
@override
Widget build(BuildContext context) {
return build(context);
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
print("dispose 离开${pageName}界面");
print("销毁${pageName}界面");
FlutterBlUmpushPlugin.umengOutViewWithName(pageName);
}
}
2,实现一个push函数,做统一的界面跳转,利用Future的特性做界面的离开,进入逻辑处理:
//跳转界面
void push({Widget page, Function popCallback}) {
print("push: 离开${pageName}界面");
FlutterBlUmpushPlugin.umengOutViewWithName(pageName);
Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) {
return page;
})).then((data) {
print("pop 进入${pageName}界面");
FlutterBlUmpushPlugin.umengEnterViewWithName(pageName);
if (popCallback != null) {
popCallback(data);
}
});
}
//路由跳转
void routerPush({String route, Function popCallback}) {
print("routerPush: 离开${pageName}界面");
FlutterBlUmpushPlugin.umengOutViewWithName(pageName);
AppRoutesManager.router.navigateTo(context, route).then((data) {
print("pop 进入${pageName}界面");
FlutterBlUmpushPlugin.umengEnterViewWithName(pageName);
if (popCallback != null) {
popCallback(data);
}
});
}
使用:
class MinePage extends StatefulWidget {
@override
_MinePageState createState() => _MinePageState();
}
class _MinePageState extends BaseState<MinePage> with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true;
@override
void initState() {
// TODO: implement initState
pageName = "个人中心";
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: pageName,
),
body: GestureDetector(
onTap: () {
routerPush(route: AppRoutesManager.mall, popCallback: (data) {});
},
child: Container(
color: Colors.red,
),
),
);
}
}
注:如果是安卓的话可以通过initState(), deactivate()加一个bool类型的参数处理,不知道为什么iOS端的deactivate()函数在push下一个界面的时候不调用。