Is there any way to detect if the user leaves the current page?
I don’t think WidgetsBinding
will work, because it handles these events by itself.
So, does anyone have any solution?
Any help is appreciated.
Get Current User Location in Flutter. Getting the user location in Flutter is made very simple by the Geolocator plugin. According to the docs, this plugin uses the native services for Android and iOS to get the location and to geocode it.
RouteObserver and RouteAware are the way to go if you want to detect if the user leaves the screen, no matter if it's by going back (popping) or pushing another context. Here's an example. Sorry for it being it a bit long, if you try it and run it you'll realize that it's pretty simple.
The following solution will not work if you also want to get notified if the user opens up another page in front of the current one. For the first case, you could use a WillPopScope . It's a class that notifies you when the enclosing ModalRoute (internally used by the Navigator) is about to be popped.
· Issue #37849 · flutter/flutter · GitHub Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community. By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
I have an easy solution if by "leaving the page" you mean that the user goes "back" from this page. The following solution will not work if you also want to get notified if the user opens up another page in front of the current one.
For the first case, you could use a WillPopScope.
It's a class that notifies you when the enclosing ModalRoute
(internally used by the Navigator
) is about to be popped. It even leaves you a choice to whether or not you want the pop to happen.
Just wrap the second screen's Scaffold
in a 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.
);
As per your description i think that you want to track your user if user press back button or return to previous screen.
You can achieve this by overriding the dispose
on your State
class.
May Following example help you to figure out your solution.
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);
}
),
),
),
);
}
}
RouteObserver and RouteAware are the way to go if you want to detect if the user leaves the screen, no matter if it's by going back (popping) or pushing another context.
Here's an example. Sorry for it being it a bit long, if you try it and run it you'll realize that it's pretty simple.
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);
},
),
],
),
),
),
);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With