I need to show an alert dialog before user navigates away from current route by pressing Back
button on Android devices. I tried to intercept back button behavior by implementing WidgetsBindingObserver
in widget state. There is an closed issue on GitHub regarding same topic. However my code is not working as the method didPopRoute() was never called. Here is my code below:
import 'dart:async';
import 'package:flutter/material.dart';
class NewEntry extends StatefulWidget {
NewEntry({Key key, this.title}) :super(key: key);
final String title;
@override
State<StatefulWidget> createState() => new _NewEntryState();
}
class _NewEntryState extends State<NewEntry> with WidgetsBindingObserver {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
Future<bool> didPopRoute() {
return showDialog(
context: context,
child: new AlertDialog(
title: new Text('Are you sure?'),
content: new Text('Unsaved data will be lost.'),
actions: <Widget>[
new FlatButton(
onPressed: () => Navigator.of(context).pop(true),
child: new Text('No'),
),
new FlatButton(
onPressed: () => Navigator.of(context).pop(false),
child: new Text('Yes'),
),
],
),
);
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
floatingActionButton: new FloatingActionButton(
child: new Icon(Icons.edit),
onPressed: () {},
),
);
}
}
In simple cases, when you need to intercept the Android back-button, you usually add WillPopScope to your widget tree. However, when developing stateful widgets that interact with the back button, it's more convenient to use the BackButtonInterceptor .
To disable back button in Flutter, you can use the WillPopScope widget. The WillPopScope widget helps you get a callback whenever the back button is pressed. Inside the callback, if you return true the screen will be popped and if you return false, you have simply disabled the back button.
You simply do: bool firstRun = await IsFirstRun. isFirstRun(); It returns true if the app is launched for the first time.
I found the solution is to use WillPopScope
widget. Here is the final code below:
import 'dart:async';
import 'package:flutter/material.dart';
class NewEntry extends StatefulWidget {
NewEntry({Key key, this.title}) :super(key: key);
final String title;
@override
State<StatefulWidget> createState() => new _NewEntryState();
}
class _NewEntryState extends State<NewEntry> {
Future<bool> _onWillPop() {
return showDialog(
context: context,
child: new AlertDialog(
title: new Text('Are you sure?'),
content: new Text('Unsaved data will be lost.'),
actions: <Widget>[
new FlatButton(
onPressed: () => Navigator.of(context).pop(false),
child: new Text('No'),
),
new FlatButton(
onPressed: () => Navigator.of(context).pop(true),
child: new Text('Yes'),
),
],
),
) ?? false;
}
@override
Widget build(BuildContext context) {
return new WillPopScope(
onWillPop: _onWillPop,
child: new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
floatingActionButton: new FloatingActionButton(
child: new Icon(Icons.edit),
onPressed: () {},
),
),
);
}
}
The back_button_interceptor
package can simplify this for you and is especially useful in more complex scenarios.
https://pub.dev/packages/back_button_interceptor#-readme-tab-
Example usage:
@override
void initState() {
super.initState();
BackButtonInterceptor.add(myInterceptor);
}
@override
void dispose() {
BackButtonInterceptor.remove(myInterceptor);
super.dispose();
}
bool myInterceptor(bool stopDefaultButtonEvent) {
print("BACK BUTTON!"); // Do some stuff.
return true;
}
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