PopScope example improvements (#142163)
Attempting to help users understand how to build a confirmation dialog when exiting a route.
This commit is contained in:
parent
e985c29f31
commit
204a8848a6
@ -62,8 +62,13 @@ class _SaveableFormState extends State<_SaveableForm> {
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _showDialog() async {
|
||||
final bool? shouldDiscard = await showDialog<bool>(
|
||||
/// Shows a dialog and resolves to true when the user has indicated that they
|
||||
/// want to pop.
|
||||
///
|
||||
/// A return value of null indicates a desire not to pop, such as when the
|
||||
/// user has dismissed the modal without tapping a button.
|
||||
Future<bool?> _showDialog() {
|
||||
return showDialog<bool>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
@ -86,19 +91,13 @@ class _SaveableFormState extends State<_SaveableForm> {
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
if (shouldDiscard ?? false) {
|
||||
// Since this is the root route, quit the app where possible by invoking
|
||||
// the SystemNavigator. If this wasn't the root route, then
|
||||
// Navigator.maybePop could be used instead.
|
||||
// See https://github.com/flutter/flutter/issues/11490
|
||||
SystemNavigator.pop();
|
||||
}
|
||||
}
|
||||
|
||||
void _save(String? value) {
|
||||
final String nextSavedValue = value ?? '';
|
||||
setState(() {
|
||||
_savedValue = value ?? '';
|
||||
_savedValue = nextSavedValue;
|
||||
_isDirty = nextSavedValue != _controller.text;
|
||||
});
|
||||
}
|
||||
|
||||
@ -112,11 +111,18 @@ class _SaveableFormState extends State<_SaveableForm> {
|
||||
const SizedBox(height: 20.0),
|
||||
Form(
|
||||
canPop: !_isDirty,
|
||||
onPopInvoked: (bool didPop) {
|
||||
onPopInvoked: (bool didPop) async {
|
||||
if (didPop) {
|
||||
return;
|
||||
}
|
||||
_showDialog();
|
||||
final bool shouldPop = await _showDialog() ?? false;
|
||||
if (shouldPop) {
|
||||
// Since this is the root route, quit the app where possible by
|
||||
// invoking the SystemNavigator. If this wasn't the root route,
|
||||
// then Navigator.maybePop could be used instead.
|
||||
// See https://github.com/flutter/flutter/issues/11490
|
||||
SystemNavigator.pop();
|
||||
}
|
||||
},
|
||||
autovalidateMode: AutovalidateMode.always,
|
||||
child: Column(
|
||||
@ -146,9 +152,9 @@ class _SaveableFormState extends State<_SaveableForm> {
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
if (_isDirty) {
|
||||
_showDialog();
|
||||
onPressed: () async {
|
||||
final bool shouldPop = !_isDirty || (await _showDialog() ?? false);
|
||||
if (!shouldPop) {
|
||||
return;
|
||||
}
|
||||
// Since this is the root route, quit the app where possible by
|
||||
|
@ -62,8 +62,13 @@ class _PageTwo extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _PageTwoState extends State<_PageTwo> {
|
||||
void _showBackDialog() {
|
||||
showDialog<void>(
|
||||
/// Shows a dialog and resolves to true when the user has indicated that they
|
||||
/// want to pop.
|
||||
///
|
||||
/// A return value of null indicates a desire not to pop, such as when the
|
||||
/// user has dismissed the modal without tapping a button.
|
||||
Future<bool?> _showBackDialog() {
|
||||
return showDialog<bool>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
@ -78,7 +83,7 @@ class _PageTwoState extends State<_PageTwo> {
|
||||
),
|
||||
child: const Text('Nevermind'),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
Navigator.pop(context, false);
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
@ -87,8 +92,7 @@ class _PageTwoState extends State<_PageTwo> {
|
||||
),
|
||||
child: const Text('Leave'),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
Navigator.pop(context);
|
||||
Navigator.pop(context, true);
|
||||
},
|
||||
),
|
||||
],
|
||||
@ -107,15 +111,21 @@ class _PageTwoState extends State<_PageTwo> {
|
||||
const Text('Page Two'),
|
||||
PopScope(
|
||||
canPop: false,
|
||||
onPopInvoked: (bool didPop) {
|
||||
onPopInvoked: (bool didPop) async {
|
||||
if (didPop) {
|
||||
return;
|
||||
}
|
||||
_showBackDialog();
|
||||
final bool shouldPop = await _showBackDialog() ?? false;
|
||||
if (context.mounted && shouldPop) {
|
||||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
child: TextButton(
|
||||
onPressed: () {
|
||||
_showBackDialog();
|
||||
onPressed: () async {
|
||||
final bool shouldPop = await _showBackDialog() ?? false;
|
||||
if (context.mounted && shouldPop) {
|
||||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
child: const Text('Go back'),
|
||||
),
|
||||
|
@ -26,8 +26,8 @@ import 'routes.dart';
|
||||
/// [PopScope], in which case it will be `false`.
|
||||
///
|
||||
/// {@tool dartpad}
|
||||
/// This sample demonstrates how to use this widget to handle nested navigation
|
||||
/// in a bottom navigation bar.
|
||||
/// This sample demonstrates showing a confirmation dialog before navigating
|
||||
/// away from a page.
|
||||
///
|
||||
/// ** See code in examples/api/lib/widgets/pop_scope/pop_scope.0.dart **
|
||||
/// {@end-tool}
|
||||
|
Loading…
x
Reference in New Issue
Block a user