Использование PopScope, чтобы убедиться, что пользователю нужно дважды нажать кнопку «Назад», чтобы выйти из приложения. Проблема в том, что после двойного нажатия кнопки «Назад» вместо выхода из приложения возвращается только пустой экран или пустой экран. Если я использую WillPopScope
, все работает так, как задумано.
Я также должен убедиться, что мое приложение использует только 1 MaterialApp внутри приложения. Вопрос в том, как правильно реализовать такое поведение для Android и iOS?
Вот пример кода:
class RootScaffold extends StatefulWidget {
final Widget body;
const RootScaffold({required this.body, super.key});
@override
State<RootScaffold> createState() => _RootScaffoldState();
}
class _RootScaffoldState extends State<RootScaffold> {
DateTime? lastBackPressTime;
bool onWillPop() {
DateTime now = DateTime.now();
if (lastBackPressTime == null ||
now.difference(lastBackPressTime!) > const Duration(seconds: 2)) {
lastBackPressTime = now;
Fluttertoast.showToast(msg: 'Press back again to exit.');
return false;
}
return true;
}
@override
Widget build(BuildContext context) {
return PopScope(
canPop: false,
onPopInvoked: (bool didPop) async {
if (didPop) {
return;
}
final shouldPop = onWillPop();
if (shouldPop && context.mounted) {
Navigator.of(context).pop();
}
},
child: Scaffold(body: widget.body),
);
}
}
Здесь есть две проблемы. Я считаю, что на Android вашу проблему можно решить, но на iOS это может быть сложно.
Итак, для Android: измените Navigator.of(context).pop();
на SystemNavigator.pop();
. Проблема здесь в том, что Navigator.of
не может вызвать системную механику для выхода из приложения. Экран просто трепещет, поэтому вы видите белый экран.
Для iOS это не сработает, так как SystemNavigator.pop()
ничего не сделает. Это задуманное поведение, поскольку оно противоречит рекомендациям Apple по дизайну: Apple рекомендует пользователям выходить из приложений с помощью кнопки «Домой» или жеста смахивания.
Я думаю, что в этой ситуации правильный путь — ничего не делать на iOS.
Попробуйте создать метод onWillPop()
Future<bool>
и конструктор and использовать Future.value([FutureOr<T>? value])
для возврата значения.
Так :
class ClickAgainToCloseWidget extends StatefulWidget {
const ClickAgainToCloseWidget({super.key});
@override
State<ClickAgainToCloseWidget> createState() =>
_ClickAgainToCloseWidgetState();
}
class _ClickAgainToCloseWidgetState extends State<ClickAgainToCloseWidget> {
DateTime? lastBackPressTime;
Future<bool> onWillPop({int neededTime = 2, required String msgToast}) {
DateTime now = DateTime.now();
if (lastBackPressTime == null ||
now.difference(lastBackPressTime!) >
Duration(
seconds: neededTime,
)) {
lastBackPressTime = now;
Fluttertoast.showToast(msg: msgToast);
return Future.value(false);
}
return Future.value(true);
}
@override
Widget build(BuildContext context) {
return PopScope(
canPop: false,
onPopInvoked: (bool didPop) async {
if (didPop) {
return;
}
final shouldPop =
await onWillPop(msgToast: 'Press back again to exit.');
if (shouldPop && context.mounted) {
Navigator.of(context).pop();
}
},
child: const Scaffold(
body: Center(
child: Text("Click Back Again To close"),
),
),
);
}
}