What is the use of WillPopScope?

#navigation#willpopscope#popscope#android#back-button

Answer

Overview

text
WillPopScope
was a Flutter widget used to intercept back button presses and control navigation behavior. However, it has been deprecated since Flutter 3.12.0 and replaced by
text
PopScope
to support Android 14's predictive back gesture feature.

Why WillPopScope Was Used

Before deprecation,

text
WillPopScope
allowed developers to:

  • Prevent users from accidentally leaving a screen
  • Show confirmation dialogs before exiting
  • Handle unsaved changes
  • Control back navigation behavior

WillPopScope Example (Deprecated)

dart
class MyForm extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async {
        // Show dialog and return true to allow pop, false to prevent
        return await showDialog(
          context: context,
          builder: (context) => AlertDialog(
            title: Text('Are you sure?'),
            content: Text('Do you want to leave this page?'),
            actions: [
              TextButton(
                onPressed: () => Navigator.of(context).pop(false),
                child: Text('No'),
              ),
              TextButton(
                onPressed: () => Navigator.of(context).pop(true),
                child: Text('Yes'),
              ),
            ],
          ),
        ) ?? false;
      },
      child: Scaffold(
        appBar: AppBar(title: Text('Form')),
        body: Center(child: Text('Form content')),
      ),
    );
  }
}

Migration to PopScope

The new

text
PopScope
widget is required for Android 14's predictive back gesture, where the back animation begins immediately when the user starts the gesture.

Key Differences

FeatureWillPopScopePopScope
TimingAsynchronous (decides during pop)Synchronous (set ahead of time)
Android 14 SupportNoYes
Predictive BackNot supportedFully supported
API StyleCallback-basedDeclarative
DeprecatedYes (v3.12.0+)Current

PopScope Example (Current)

dart
class MyForm extends StatefulWidget {
  
  State<MyForm> createState() => _MyFormState();
}

class _MyFormState extends State<MyForm> {
  bool _hasUnsavedChanges = false;

  
  Widget build(BuildContext context) {
    return PopScope(
      canPop: !_hasUnsavedChanges, // Set ahead of time
      onPopInvoked: (bool didPop) {
        if (didPop) {
          return;
        }
        // Show dialog when canPop is false
        _showBackDialog();
      },
      child: Scaffold(
        appBar: AppBar(title: Text('Form')),
        body: TextField(
          onChanged: (value) {
            setState(() {
              _hasUnsavedChanges = value.isNotEmpty;
            });
          },
        ),
      ),
    );
  }

  void _showBackDialog() {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: Text('Unsaved changes'),
        content: Text('Are you sure you want to leave?'),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(),
            child: Text('Cancel'),
          ),
          TextButton(
            onPressed: () {
              Navigator.of(context).pop();
              Navigator.of(context).pop(); // Actually leave
            },
            child: Text('Leave'),
          ),
        ],
      ),
    );
  }
}

Why the Change?

Android 14 introduced predictive back gestures where:

  • The back animation begins immediately when the gesture starts
  • The app cannot decide whether to allow the pop during the gesture
  • The decision must be known ahead of time using the
    text
    canPop
    boolean

Best Practices

  • Migrate to PopScope for Flutter 3.12.0+ projects
  • Use
    text
    canPop
    to declare navigation behavior upfront
  • Implement
    text
    onPopInvoked
    for confirmation dialogs
  • Test on Android 14+ devices for predictive back gestures
  • Update to Flutter 3.14.0-7.0.pre or greater for full support

Official Documentation