What is the use of WillPopScope?
#navigation#willpopscope#popscope#android#back-button
Answer
Overview
text
WillPopScopetext
PopScopeWhy WillPopScope Was Used
Before deprecation,
text
WillPopScope- Prevent users from accidentally leaving a screen
- Show confirmation dialogs before exiting
- Handle unsaved changes
- Control back navigation behavior
WillPopScope Example (Deprecated)
dartclass 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
PopScopeKey Differences
| Feature | WillPopScope | PopScope |
|---|---|---|
| Timing | Asynchronous (decides during pop) | Synchronous (set ahead of time) |
| Android 14 Support | No | Yes |
| Predictive Back | Not supported | Fully supported |
| API Style | Callback-based | Declarative |
| Deprecated | Yes (v3.12.0+) | Current |
PopScope Example (Current)
dartclass 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 booleantext
canPop
Best Practices
- Migrate to PopScope for Flutter 3.12.0+ projects
- Use to declare navigation behavior upfronttext
canPop - Implement for confirmation dialogstext
onPopInvoked - Test on Android 14+ devices for predictive back gestures
- Update to Flutter 3.14.0-7.0.pre or greater for full support