catch Android back button event on Flutter
AndroidDartFlutterAndroid Problem Overview
Is there any way I can catch the onBackPressed
event from Android back button?
I've tried the WillPopScope
but my onWillPop
function only triggered when I tap on the Material back arrow button
I put it like this:
class MyView extends StatelessWidget{
Widget build(BuildContext context) {
return new WillPopScope(
onWillPop: () async {
debugPrint("Will pop");
return true;
},
child: ScopedModel<AppModel>(
model: new AppModel(),
child: new Scaffold(......
I need to catch it because somehow my screen behaved incorrectly when it came to back button pressed, it pops the screen and the screen below it, but somehow, using material back arrow button works normal.
Update:
The code works, my problem was not in the pop of this screen, but on the previous screen, I use 2 MaterialApp widgets, and somehow it gave a weird behavior.
Android Solutions
Solution 1 - Android
In order to prevent navigating back WillPopScope is the correct way and should be used as follow:
class Page2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new WillPopScope(
child: new Scaffold(
appBar: new AppBar(
title: new Text('Page 2'),
),
body: new Center(
child: new Text('PAGE 2'),
),
),
onWillPop: () async {
return false;
},
);
}
}
Future<T> pushPage<T>(BuildContext context, Widget page) {
return Navigator.of(context)
.push<T>(MaterialPageRoute(builder: (context) => page));
}
Can call the page like:
pushPage(context, Page2());
Solution 2 - Android
This is should be helpful.
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () {
_moveToScreen2(context, );
},
child: Scaffold(
key: _scaffoldKey,
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
_moveToScreen2(context);
}),
title: Text("Screen 1"),
),
),
);
}
/**
* This is probably too thin to be in its own method - consider using
* `Navigator.pushReplacementNamed(context, "screen2")` directly
*/
void _moveToScreen2(BuildContext context) =>
Navigator.pushReplacementNamed(context, "screen2");
Solution 3 - Android
Use WillPopScope method and return false
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
// Do something here
print("After clicking the Android Back Button");
return false;
},
child: Scaffold(
appBar: AppBar(
title: Text("Handling the back button"),
),
body: Center(
child: Text("Body"),
),
),
);
}
Solution 4 - Android
This code work for me.
I think there may be two reasons.
-
Child of WillPopScope is Scaffold
-
No return in onWillPop
return new WillPopScope( onWillPop: () { if (!_isOpened) Navigator.pop(context); }, child: new Scaffold( key: SharedService.orderScaffoldKey, appBar: appBar, body: new Builder( builder: (BuildContext context) { return page; }, ), ), );
Solution 5 - Android
Just adding an important point here.
Please note that by using WillPopScope
, we will lose the back swipe gesture on iOS.
Solution 6 - Android
Another way todo this is to implement a NavigatorObserver
and link it to the MaterialApp
:
https://api.flutter.dev/flutter/widgets/RouteObserver-class.html
You don't have to use RouteAware
, you can also implement your own NavigatorObserver
.
This is for example how Flutter analytics works to automatically track screen opens/closes:
MaterialApp(
...
navigatorObservers: [
FirebaseAnalyticsObserver(analytics: analytics),
],
)
FirebaseAnalyticsObserver
extends the RouteObserver
which itself implements NavigatorObserver
.
However WillPopScope
is often the easier solution