有什么方法可以检测用户是否离开当前页面?
我认为WidgetsBinding
不会起作用,因为它可以自行处理这些事件。
那么,有人有什么解决方案吗?
任何帮助表示赞赏。
答案 0 :(得分:3)
RouteObserver 和 RouteAware 如果您想检测用户是否离开屏幕,无论是返回(弹出)还是推送另一个上下文,都可以使用 RouteObserver 和 RouteAware。
这是一个例子。抱歉,它有点长,如果您尝试并运行它,您会发现它非常简单。
import 'package:flutter/material.dart';
void main() async {
runApp(App());
}
class App extends StatelessWidget {
static final RouteObserver<PageRoute> routeObserver =
RouteObserver<PageRoute>();
@override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: '/',
navigatorObservers: [routeObserver],
routes: {
'/': (context) => Screen1(),
'screen2': (context) => Screen2(),
},
);
}
}
class ScreenWrapper extends StatefulWidget {
final Widget child;
final Function() onLeaveScreen;
final String routeName;
ScreenWrapper({this.child, this.onLeaveScreen, @required this.routeName});
@override
State<StatefulWidget> createState() {
return ScreenWrapperState();
}
}
class ScreenWrapperState extends State<ScreenWrapper> with RouteAware {
@override
Widget build(BuildContext context) {
return widget.child;
}
void onLeaveScreen() {
if (widget.onLeaveScreen != null) {
widget.onLeaveScreen();
}
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
App.routeObserver.subscribe(this, ModalRoute.of(context));
}
@override
void dispose() {
super.dispose();
App.routeObserver.unsubscribe(this);
}
@override
void didPush() {
print('*** Entering screen: ${widget.routeName}');
}
void didPushNext() {
print('*** Leaving screen: ${widget.routeName}');
onLeaveScreen();
}
@override
void didPop() {
print('*** Going back, leaving screen: ${widget.routeName}');
onLeaveScreen();
}
@override
void didPopNext() {
print('*** Going back to screen: ${widget.routeName}');
}
}
class Screen1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ScreenWrapper(
onLeaveScreen: () {
print("***** Here's my special handling for leaving screen1!!");
},
routeName: '/',
child: Scaffold(
backgroundColor: Colors.yellow,
body: SafeArea(
child: Column(
children: [
Text('This is Screen1'),
FlatButton(
child: Text('Press here to go to screen 2'),
onPressed: () {
Navigator.pushNamed(context, 'screen2');
},
),
FlatButton(
child: Text(
"Press here to go back (only works if you've pushed before)"),
onPressed: () {
Navigator.maybePop(context);
},
),
],
),
),
),
);
}
}
class Screen2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ScreenWrapper(
routeName: 'screen2',
child: Scaffold(
backgroundColor: Colors.blue,
body: SafeArea(
child: Column(
children: [
Text('This is Screen2'),
FlatButton(
child: Text('Press here to go to screen 1'),
onPressed: () {
Navigator.pushNamed(context, '/');
},
),
FlatButton(
child: Text(
"Press here to go back (only works if you've pushed before)"),
onPressed: () {
Navigator.maybePop(context);
},
),
],
),
),
),
);
}
}
答案 1 :(得分:1)
根据您的描述,我认为如果用户按下“后退”按钮或返回上一屏幕,则希望跟踪您的用户。
以下示例可以帮助您找出解决方案。
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: EventRow(),
);
}
}
class EventRow extends StatelessWidget {
@override
Widget build (BuildContext context) {
return Scaffold(
appBar: new AppBar(
title: new Text("Demo"),
),
body: Center(
child: Container(
child: new RaisedButton(
onPressed: (){
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondScreen()),
);
},
child: Text("Goto Second Scrren"),
),
),
),
);
}
}
class SecondScreen extends StatefulWidget {
@override
_SecondScreenState createState() => _SecondScreenState();
}
class _SecondScreenState extends State<SecondScreen> {
@override
void initState() {
// TODO: implement initState
super.initState();
}
@override
void dispose() {
// TODO: implement dispose
print("Back To old Screen");
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: new Center(
child: new Container(
child: new RaisedButton(
child: Text("Goto First Scrren"),
onPressed: (){
Navigator.pop(context);
}
),
),
),
);
}
}
答案 2 :(得分:1)
我最近遇到了这样一种情况,我需要检测路径的变化以弹出当前路径或从当前路径推到新路径,而我能够通过从RouteObserver获得回答here。
使用WillPopScope
,您可以在路由(弹出)发生之前检测出可能的更改,并确定是否应该允许或拒绝。如果您只是想在弹出后执行某项操作,可以通过覆盖onDispose
来完成。
答案 3 :(得分:1)
您可以通过覆盖dispose()
方法来实现。
答案 4 :(得分:-1)
我有一个简单的解决方案,如果通过“离开页面”来表示用户从该页面“返回”。如果您还希望在用户打开当前页面之前的另一页面时得到通知,则以下解决方案将不起作用。
对于第一种情况,您可以使用WillPopScope。
当要封闭的ModalRoute
(由Navigator
内部使用)弹出时,此类会通知您。它甚至使您可以选择是否要弹出。
只需将第二个屏幕的Scaffold
包装在WillPopScope
中。
return WillPopScope(
onWillPop: () async {
// You can do some work here.
// Returning true allows the pop to happen, returning false prevents it.
return true;
},
child: ... // Your Scaffold goes here.
);