我有一个带有自动对焦文本字段的警报对话框,因此当警报对话框打开时,键盘会自动打开。但是,如果我在 Android 上按后退按钮,则只会关闭键盘,并且我需要再次按后退按钮才能关闭对话框。 我在 TextField 的 OnSubscribed 回调中具有所需的行为,其中我只使用 Navigator.pop(context)。但我认为这是有效的,因为我只是关闭了警报对话框,键盘也随之关闭,因为没有文本可以填充了。但是,当我按“后退”按钮时,我无法在“文本字段”或“警报对话框”中跟踪它,因此无法使用 Navigator.pop(context)。 我尝试在警报对话框、Scaffold 甚至 MaterialApp 上使用 PopScope - 它不会记录第 1 次后退按钮按下,仅记录第 2 次按下。我还尝试使用 KeyboardListener 来查找 BackButton 操作按下,但我可以让它工作。
我认为这是因为关闭键盘不会改变 TextField 的焦点,并且无法使用 PopScope 或其他方法捕获。 这是我设法使其工作的方法,但我认为这太长了并且这依赖于键盘动画。如果它更长 - 这将不起作用。
在这里,我确保窗口仅关闭一次,因为它尝试调用 Navigator.pop(context) 两次,并且它只是关闭整个应用程序页面本身并将其变为黑色。
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:todo_app/utils/global_utils.dart' as globals;
class BasicWindow extends StatefulWidget {
const BasicWindow({super.key});
@override
State<BasicWindow> createState() => _BasicWindowState();
}
class _BasicWindowState extends State<BasicWindow> {
@override
Widget build(BuildContext context) {
//make sure the build is finished
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!mounted) return;
if (globals.mobile) {
Future.delayed(const Duration(milliseconds: 400), () {
bool noKeyboardShown =
MediaQuery.of(context).viewInsets.bottom == 0.0;
if (noKeyboardShown & !globals.dialogClosed) {
globals.dialogClosed = true;
Navigator.pop(context);
Future.delayed(const Duration(milliseconds: 600), () {
globals.dialogClosed = false;
});
}
});
}
});
return AlertDialog(
content: TextField(
//focusNode: _textFocus,
onSubmitted: (value) {
Navigator.pop(context);
},
),
);
}
}
您必须使用
WillPopScope
来实现此行为。
像这样重构你的代码:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:todo_app/utils/global_utils.dart' as globals;
class BasicWindow extends StatefulWidget {
const BasicWindow({super.key});
@override
State<BasicWindow> createState() => _BasicWindowState();
}
class _BasicWindowState extends State<BasicWindow> {
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
// Close the keyboard before popping the dialog
FocusScope.of(context).unfocus();
// Close the dialog
if (!globals.dialogClosed) {
globals.dialogClosed = true;
Navigator.pop(context);
// Reset the dialogClosed flag after a delay to prevent re-triggering
Future.delayed(const Duration(milliseconds: 600), () {
globals.dialogClosed = false;
});
}
// Return true to allow the back action (closing the dialog)
return false;
},
child: AlertDialog(
content: TextField(
autofocus: true,
onSubmitted: (value) {
Navigator.pop(context);
},
),
),
);
}
}