Handling Back Navigation with PopScope in Flutter
Building Flutter apps? You'll likely face situations where you need to control the back button. Imagine a user editing a note, and you want a confirmation dialog before they accidentally ditch their work!
The old WillPopScope
widget used to handle this, but it's deprecated as of Flutter 3.12 (thanks, Android 14's new back gesture!). The new sheriff in town is PopScope
, but it doesn't quite let you block the back action directly.
After a couple hours of researching and investigating, Here's the solution to get PopScope
to mimic WillPopScope
:
@override
Widget build(BuildContext context) {
return PopScope(
canPop: false,
onPopInvokedWithResult: (bool didPop, object? result) async {
if (!didPop) {
final navigator = Navigator.of(context);
if (_noteController.text.isEmpty || (_noteController.text.isNotEmpty && (await _showUnsavedChangesDialog(context) ?? false))) {
navigator.pop();
}
}
},
child: Scaffold(
...
and the following shows the difference:
@override
Widget build(BuildContext context) {
- return WillPopScope(
- onWillPop: () async {
- if (_noteController.text.isNotEmpty) {
+ return PopScope(
+ canPop: false,
+ onPopInvokedWithResult: (bool didPop, object? result) async {
+ if (!didPop) {
+ final navigator = Navigator.of(context);
+ if (_noteController.text.isEmpty || (_noteController.text.isNotEmpty && (await _showUnsavedChangesDialog(context) ?? false))) {
+ navigator.pop();
+ }
- final shouldPop = await _showUnsavedChangesDialog(context);
- return shouldPop ?? false;
}
- return true;
},
child: Scaffold(
Here's how this solution works:
canPop
is set tofalse
, disabling the system back gesture.- In the
onPopInvokedWithResult
callback, it checks ifdidPop
is false (indicating that the pop operation hasn't occurred yet) - Then, it checks if there aren't any unsaved changes
_noteController.text.isEmpty
, or, although there are unsaved changes (_noteController.text.isNotEmpty
), the user answersYes
when asking confirmation. - If any of the conditions are true, it manually triggers the pop operation by calling
navigator.pop()
. Otherwise, do nothing.
By disabling the system back gesture (canPop: false
) and manually triggering the pop operation (navigator.pop()
), this solution allows you to perform necessary actions (e.g., showing a confirmation dialog) before the pop operation occurs, effectively replicating the behavior of WillPopScope
.
I hope it helps!