You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中键盘遮挡表单且弹出后立即关闭的问题解决

问题分析与解决方案

核心问题根源

  1. 状态丢失导致键盘闪退:PageController、formKey、TextEditingController均在build方法内创建,每次页面重建都会生成新实例,直接导致输入框焦点丢失、键盘弹出后立即关闭。
  2. 页面未适配键盘:Scaffold设置了resizeToAvoidBottomInset: false,禁止了键盘弹出时的页面自适应调整逻辑。
  3. 固定高度限制滚动:多层嵌套的固定高度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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 09:37:05