Flutter中键盘遮挡表单且弹出后立即关闭的问题解决
问题分析与解决方案
核心问题根源
- 状态丢失导致键盘闪退:
PageController、formKey、TextEditingController均在build方法内创建,每次页面重建都会生成新实例,直接导致输入框焦点丢失、键盘弹出后立即关闭。 - 页面未适配键盘:Scaffold设置了
resizeToAvoidBottomInset: false,禁止了键盘弹出时的页面自适应调整逻辑。 - 固定高度限制滚动:多层嵌套的固定高度
SizedBox限制了滚动区域,导致表单无法随键盘弹出正常上移。
解决方案步骤
1. 重构State类,将控制器移至成员变量
把控制器和全局键从build方法中移出,在组件生命周期内保持唯一实例,避免状态丢失:
class _CheckoutPageState extends State<CheckoutPage> with TickerProviderStateMixin { Map<String, bool> isActive = { 'Quantity': true, 'Payment': false, 'Review': false, }; Map<String, bool> isDone = { 'Quantity': false, 'Payment': false, 'Review': false, }; // 声明为成员变量 late PageController pageViewController; late GlobalKey<FormState> formKey; late TextEditingController nameController; late TextEditingController phoneNumberController; late TextEditingController addressController; late Order order; @override void initState() { super.initState(); // 初始化资源 pageViewController = PageController(); formKey = GlobalKey<FormState>(); nameController = TextEditingController(); phoneNumberController = TextEditingController(); addressController = TextEditingController(); } @override void didChangeDependencies() { super.didChangeDependencies(); // 在这里获取路由参数,避免build重复执行 order = ModalRoute.of(context)!.settings.arguments as Order; } @override void dispose() { // 销毁资源,避免内存泄漏 pageViewController.dispose(); nameController.dispose(); phoneNumberController.dispose(); addressController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final double height = MediaQuery.of(context).size.height; return Scaffold( // 开启键盘适配 resizeToAvoidBottomInset: true, body: Stack( children: [ Column( children: [ SizedBox( height: height * 0.16, child: PageViewIndicator(isActive: isActive, isDone: isDone), ), // 用Expanded替代固定高度,让PageView自适应剩余空间 Expanded( child: Padding( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 18, ), child: PageView( controller: pageViewController, children: [ QuantityStepWidget( formKey: formKey, addressController: addressController, nameController: nameController, phoneNumberController: phoneNumberController, ), const PaymentStepWidget(), const ReviewStepWidget(), ], ), ), ), ], ), const BackButtonWidget(), ], ), ); } }
2. 优化QuantityStepWidget布局,移除冗余固定高度
去掉多层嵌套的固定高度容器,让滚动视图正常工作,并添加键盘适配间距:
class QuantityStepWidget extends StatelessWidget { final GlobalKey<FormState> formKey; final TextEditingController nameController; final TextEditingController phoneNumberController; final TextEditingController addressController; const QuantityStepWidget( {super.key, required this.formKey, required this.nameController, required this.phoneNumberController, required this.addressController}); @override Widget build(BuildContext context) { return SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const TitleWidget(title: 'Quantity'), const SizedBox(height: 16), MedicationCheckoutQuantityWidget(order: order), const SizedBox(height: 24), const Text( 'Confirm your information', style: kH3TitleStyle, ), const SizedBox(height: 10), Form( key: formKey, child: Column( children: [ TextFormFieldUserInformationsConfirmationWidget( type: FormType.name, controller: nameController, ), const SizedBox(height: 12), TextFormFieldUserInformationsConfirmationWidget( type: FormType.phoneNumber, controller: phoneNumberController, ), const SizedBox(height: 12), TextFormFieldUserInformationsConfirmationWidget( type: FormType.address, controller: addressController, ), ], ), ), const SizedBox(height: 32), ButtonWidget( onPressed: () { if (formKey.currentState!.validate()) { print(nameController.text); print(phoneNumberController.text); print(addressController.text); } }, text: 'Confirm'), // 添加底部间距,避免键盘遮挡按钮 SizedBox(height: MediaQuery.of(context).viewInsets.bottom), ], ), ); } }
内容的提问来源于stack exchange,提问作者Mikelenjilo
相关产品推荐
相关产品推荐

