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

Flutter键盘遮挡底部输入框问题求助

解决Flutter键盘遮挡输入框且ListView滚动后自动回滚的问题

问题原因

你当前使用shrinkWrap: true的ListView会让列表高度完全适配内容,当键盘弹出时页面布局重排,导致滚动位置自动重置;同时未处理键盘弹出时的底部间距,最终引发输入框被遮挡的问题。

解决方案

推荐替换ListView为SingleChildScrollView + Column的组合,配合MediaQuery添加键盘弹出时的动态底部padding,这是处理此类场景最稳定的方案:

return SingleChildScrollView(
  keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.manual,
  // 动态添加底部padding,避免键盘遮挡输入框
  padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
  child: Column(
    mainAxisSize: MainAxisSize.min,
    children: [
      SizedBox(
        width: 100,
        height: 100,
        child: Image.network(state.specificPaymentTypeModels.icon),
      ),
      Container(
        margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
        child: Text(
          state.specificPaymentTypeModels.title,
          textAlign: TextAlign.center,
        ),
      ),
      SizedBox(
          width: width / 1.5,
          child: Html(
            data: state.specificPaymentTypeModels.description,
          )),
      state.specificPaymentTypeModels.alias == 'freedom-pay' ||
              state.specificPaymentTypeModels.alias == 'balancekg' ||
              state.specificPaymentTypeModels.alias == 'megapay' ||
              state.specificPaymentTypeModels.alias == 'odengi'
          ? Container(
              margin: EdgeInsets.only(top: 15),
              child: MyTextField(
                hint: 'Введите сумму пополнения',
                myController: summa,
              ))
          : Container(),
      state.specificPaymentTypeModels.alias == 'megapay' ||
              state.specificPaymentTypeModels.alias == 'balancekg'
          ? Container(
              margin: const EdgeInsets.fromLTRB(16, 10, 16, 0),
              decoration: BoxDecoration(
                border: Border(
                    top: BorderSide(
                        color: ConfigColor.lightGrey, width: 1.5),
                    bottom: BorderSide(
                        color: ConfigColor.lightGrey, width: 1.5),
                    right: BorderSide(
                        color: ConfigColor.lightGrey, width: 1.5),
                    left: BorderSide(
                        color: ConfigColor.lightGrey, width: 1.5)),
                color: Colors.white,
              ),
              child: TextField(
                controller: number,
                inputFormatters: [maskFormatter],
                style: TextStyle(
                  color: ConfigColor.textBlack,
                  fontWeight: FontWeight.w400,
                ),
                decoration: InputDecoration(
                    hintText: '996 (707)-098-995',
                    hintStyle: TextStyle(
                      fontSize: 16,
                      color: Colors.grey,
                      fontWeight: FontWeight.w400,
                    ),
                    fillColor: Colors.white,
                    filled: true,
                    border: OutlineInputBorder(
                        borderRadius: BorderRadius.circular(4),
                        borderSide: BorderSide.none)),
              ))
          : Container(),
      state.specificPaymentTypeModels.alias == 'freedom-pay' ||
              state.specificPaymentTypeModels.alias == 'balancekg' ||
              state.specificPaymentTypeModels.alias == 'megapay' ||
              state.specificPaymentTypeModels.alias == 'odengi'
          ? InkWell(
              onTap: () async {
                await context.read<ReciveTypeCubit>()
                  ..reciveType(
                          number.text == null
                              ? '123456789123'
                              : '996${maskFormatter.getUnmaskedText()}',
                          state.specificPaymentTypeModels.alias,
                          int.parse(summa.text))
                      .whenComplete(() async {
                    context.go('/reciveType');
                    final prefs = await SharedPreferences.getInstance();
                    await prefs.setString('phoneNumberPayments',
                        '996${maskFormatter.getUnmaskedText()}');
                    print(await prefs.getString('phoneNumberPayments'));
                  });
              },
              child: Container(
                width: double.infinity,
                margin: EdgeInsets.only(top: 15),
                padding: const EdgeInsets.symmetric(vertical: 12),
                decoration: BoxDecoration(
                    color: ConfigColor.green,
                    borderRadius: BorderRadius.circular(32)),
                child: Text(
                  'Готово',
                  textAlign: TextAlign.center,
                  style: TextStyle(
                      color: Colors.white,
                      fontWeight: FontWeight.w500,
                      fontSize: 16),
                ),
              ),
            )
          : Container()
    ],
  ),
);

额外说明

如果一定要保留ListView,需要做两个关键修改:

  1. 移除shrinkWrap: true,并用Expanded包裹ListView,给它一个确定的父布局高度
  2. 添加底部动态padding:padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom)

这样能避免滚动后自动回滚的问题,同时确保输入框不被键盘遮挡。

内容的提问来源于stack exchange,提问作者Daniil

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 09:52:57