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:

  1. canPop is set to false, disabling the system back gesture.
  2. In the onPopInvokedWithResult callback, it checks if didPop is false (indicating that the pop operation hasn't occurred yet)
  3. Then, it checks if there aren't any unsaved changes _noteController.text.isEmpty, or, although there are unsaved changes (_noteController.text.isNotEmpty), the user answers Yes when asking confirmation.
  4. 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!

Comments

  1. Markdown is allowed. HTML tags allowed: <strong>, <em>, <blockquote>, <code>, <pre>, <a>.