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

Flutter中FAB搭配键盘时RenderFlex溢出错误的解决方法

解决FAB集成输入框时的RenderFlex溢出问题

以下是针对该问题的具体修复方案:

核心问题分析

你的FAB使用了固定高度的Container,当TextFormField触发验证错误显示提示文本时,内容高度超过容器固定高度;同时body部分的Column布局未正确处理剩余空间,导致键盘弹出时布局挤压溢出。

具体修复步骤

1. 移除FAB容器的固定高度

去掉Container的height属性,改用Padding控制上下内边距,让容器自适应内容高度:

floatingActionButton: Container(
  width: ScreenSize.screenWidth*0.95,
  decoration: BoxDecoration(
    color: Colors.white,
    borderRadius: BorderRadius.circular(8),
  ),
  padding: const EdgeInsets.symmetric(vertical: 8.0), // 替换固定高度为内边距
  child: ... // 原有Row内容
),

2. 优化TextFormField的空间适配

给TextFormField添加行数控制属性,同时限制错误提示行数,避免高度突增:

TextFormField(
  controller: _txtController,
  minLines: 1,
  maxLines: 3, // 允许输入框根据内容换行
  decoration: InputDecoration(
    // 原有装饰内容
    errorMaxLines: 2, // 限制错误提示行数
  ),
  validator: (value) {
    if (value!.isEmpty) {
      return "Please enter a message";
    }
    return null;
  },
),

3. 修复Body部分的布局嵌套问题

原布局中SingleChildScrollView嵌套ListView会导致滚动冲突,且Column的MainAxisAlignment.spaceBetween无意义(仅一个子元素),改用Expanded包裹ListView,让聊天列表占据剩余空间:

body: SafeArea(
  child: Column(
    children: [
      Expanded( // 用Expanded让列表占据剩余空间
        child: Padding(
          padding: const EdgeInsets.symmetric(vertical: 8.0),
          child: Consumer<MainProvider>(
            builder: (context, value, child) => isLoading 
                ? const Center(child: CircularProgressIndicator())
                : ListView.builder(
                    padding: const EdgeInsets.symmetric(horizontal: 8.0),
                    itemCount: value.chats.length,
                    itemBuilder: (context, index) {
                      debugPrint("${value.chats[index].erpId} == ${userP!.erp!}");
                      return Column(
                        children: [
                          BubbleSpecialThree(
                            text: value.chats[index].message!,
                            color: const Color(0xFF1B97F3),
                            tail: true,
                            isSender: value.chats[index].sentBy == userP.erp!
                                ? true
                                : false,
                            sent: value.chats[index].isReply==null ? true : !(value.chats[index].isReply!),
                            seen: value.chats[index].readAt==null || value.chats[index].readAt=='' ? false : true,
                            delivered: true,
                            key: ValueKey(value.chats[index]),
                            textStyle: const TextStyle(
                                color: Colors.white, fontSize: 16),
                          ),
                        ],
                      ).py8();
                    },
                  ),
          ),
        ),
      ),
    ],
  ),
),

4. 调整FAB内部Row布局

将Row的crossAxisAlignment改为CrossAxisAlignment.start,避免内容垂直居中导致的挤压,同时移除多余的SingleChildScrollView:

child: Row(
  mainAxisAlignment: MainAxisAlignment.center,
  crossAxisAlignment: CrossAxisAlignment.start, // 修改为顶部对齐
  children: [
    Padding(
      padding: const EdgeInsets.symmetric(vertical: 4.0),
      child: SizedBox(
        width: context.screenWidth * 0.75,
        child: Form(
          key: _formKey,
          child: TextFormField(
            // 原有TextFormField内容
          ),
        ),
      ),
    ),
    SizedBox(width: context.screenWidth * 0.04),
    IconButton(
      // 原有IconButton内容
    ).centered()
  ],
),

修改后的完整代码片段

Scaffold(
  backgroundColor: const Color(0xfff5f5f5),
  resizeToAvoidBottomInset: true,
  floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
  floatingActionButton: Container(
    width: ScreenSize.screenWidth*0.95,
    decoration: BoxDecoration(
      color: Colors.white,
      borderRadius: BorderRadius.circular(8),
    ),
    padding: const EdgeInsets.symmetric(vertical: 8.0),
    child: Row(
      mainAxisAlignment: MainAxisAlignment.center,
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Padding(
          padding: const EdgeInsets.symmetric(vertical: 4.0),
          child: SizedBox(
            width: context.screenWidth * 0.75,
            child: Form(
              key: _formKey,
              child: TextFormField(
                controller: _txtController,
                minLines: 1,
                maxLines: 3,
                decoration: InputDecoration(
                  alignLabelWithHint: true,
                  label: Text(
                    "Type a message*",
                    textAlign: TextAlign.start,
                    style: TextStyle(
                      overflow: TextOverflow.visible,
                      fontSize: 16,
                      fontWeight: FontWeight.w400,
                      color: const Color(0xFF1C1B1F).withOpacity(.74),
                    ),
                  ),
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(10),
                  ),
                  errorMaxLines: 2,
                ),
                validator: (value) {
                  if (value!.isEmpty) {
                    return "Please enter a message";
                  }
                  return null;
                },
              ),
            ),
          ),
        ),
        SizedBox(width: context.screenWidth * 0.04),
        IconButton(
            onPressed: () async {
              debugPrint("Saved Id: ${userP!.erp!}, sent id: ${widget.data.result!.user!.username} and name is: ${widget.data.result?.user?.name}");
              if (_formKey.currentState!.validate()) {
                setState(() {
                  change=false;
                });
                final WhatAppMsgModel data = WhatAppMsgModel(
                  message: _txtController.text,
                  sentAt: DateTime.now(),
                  sentBy: userP.erp,
                  erpId: widget.data.result?.user?.username,
                  teacherErp: userP.erp,
                  activityId: widget.data.result!.activity!.toString(),
                  contact: widget.data.result!.user!.contactNo!,
                  isReply: false,
                );

                bool isDone = await ActivityServices().sendWhatsAppMessages(
                  data: data,
                  isClasswise: widget.data.isClasswise!,
                );
                if (isDone) {
                  debugPrint("Yes, sent");
                  chatP.addMessage(data);
                  _txtController.clear();
                  FocusManager.instance.primaryFocus?.unfocus();
                } else {
                  debugPrint("Nope");
                  if (context.mounted) {
                    ScaffoldMessenger.of(context)
                        .showSnackBar(const SnackBar(
                      content: Text("Something went wrong"),
                    ));
                  }
                }
              }
              else {
                setState(() {
                  change=true;
                });
              }
            },
            icon: const Icon(
              Icons.send,
              size: 36,
            )).centered()
      ],
    ),
  ),
  appBar: AppBar(
    backgroundColor: Colors.blueAccent,
    title: const Text('Conversation'),
  ),
  body: SafeArea(
    child: Column(
      children: [
        Expanded(
          child: Padding(
            padding: const EdgeInsets.symmetric(vertical: 8.0),
            child: Consumer<MainProvider>(
              builder: (context, value, child) => isLoading 
                  ? const Center(child: CircularProgressIndicator())
                  : ListView.builder(
                      padding: const EdgeInsets.symmetric(horizontal: 8.0),
                      itemCount: value.chats.length,
                      itemBuilder: (context, index) {
                        debugPrint("${value.chats[index].erpId} == ${userP!.erp!}");
                        return Column(
                          children: [
                            BubbleSpecialThree(
                              text: value.chats[index].message!,
                              color: const Color(0xFF1B97F3),
                              tail: true,
                              isSender: value.chats[index].sentBy == userP.erp!
                                  ? true
                                  : false,
                              sent: value.chats[index].isReply==null ? true : !(value.chats[index].isReply!),
                              seen: value.chats[index].readAt==null || value.chats[index].readAt=='' ? false : true,
                              delivered: true,
                              key: ValueKey(value.chats[index]),
                              textStyle: const TextStyle(
                                  color: Colors.white, fontSize: 16),
                            ),
                          ],
                        ).py8();
                      },
                    ),
            ),
          ),
        ),
      ],
    ),
  ),
),

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 06:52:04