Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect if the user leaves the current page in Flutter?

Tags:

flutter

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.

like image 386
Daibaku Avatar asked Oct 29 '18 03:10

Daibaku


People also ask

How to get current user location in flutter?

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.

How can I detect when a user leaves the screen?

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.

How to get notified when a user opens another 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.

What is the issue number for flutter on GitHub?

· 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.


3 Answers

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.
);
like image 149
Marcel Avatar answered Oct 08 '22 10:10

Marcel


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);
              }
          ),
        ),
      ),
    );
  }
}
like image 25
Viren V Varasadiya Avatar answered Oct 08 '22 09:10

Viren V Varasadiya


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);
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}
like image 10
Michael Kjellander Avatar answered Oct 08 '22 11:10

Michael Kjellander